Mercurial > illumos > illumos-gate
changeset 7042:46fc4b6db23e
6721094 Setting certain properties on root pools should not be allowed
author | gw25295 |
---|---|
date | Mon, 07 Jul 2008 10:11:14 -0700 |
parents | b4c5fe87fad8 |
children | 22affca31e0f |
files | usr/src/grub/grub-0.95/stage2/fsys_zfs.c usr/src/lib/libzfs/common/libzfs.h usr/src/lib/libzfs/common/libzfs_dataset.c usr/src/lib/libzfs/common/libzfs_pool.c usr/src/lib/libzfs/common/libzfs_util.c usr/src/uts/common/fs/zfs/spa.c usr/src/uts/common/fs/zfs/sys/spa_impl.h usr/src/uts/common/fs/zfs/sys/vdev.h usr/src/uts/common/fs/zfs/vdev.c usr/src/uts/common/fs/zfs/zfs_ioctl.c |
diffstat | 10 files changed, 192 insertions(+), 36 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/grub/grub-0.95/stage2/fsys_zfs.c Fri Jul 04 13:08:26 2008 -0700 +++ b/usr/src/grub/grub-0.95/stage2/fsys_zfs.c Mon Jul 07 10:11:14 2008 -0700 @@ -64,10 +64,11 @@ 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 */ }; /*
--- a/usr/src/lib/libzfs/common/libzfs.h Fri Jul 04 13:08:26 2008 -0700 +++ b/usr/src/lib/libzfs/common/libzfs.h Mon Jul 07 10:11:14 2008 -0700 @@ -115,6 +115,7 @@ 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 };
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c Fri Jul 04 13:08:26 2008 -0700 +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c Mon Jul 07 10:11:14 2008 -0700 @@ -1868,6 +1868,17 @@ (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.
--- a/usr/src/lib/libzfs/common/libzfs_pool.c Fri Jul 04 13:08:26 2008 -0700 +++ b/usr/src/lib/libzfs/common/libzfs_pool.c Mon Jul 07 10:11:14 2008 -0700 @@ -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 @@ } /* + * 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 @@ 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 @@ (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 @@ #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 @@ { 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 @@ &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); }
--- a/usr/src/lib/libzfs/common/libzfs_util.c Fri Jul 04 13:08:26 2008 -0700 +++ b/usr/src/lib/libzfs/common/libzfs_util.c Mon Jul 07 10:11:14 2008 -0700 @@ -206,6 +206,9 @@ 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:
--- a/usr/src/uts/common/fs/zfs/spa.c Fri Jul 04 13:08:26 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/spa.c Mon Jul 07 10:11:14 2008 -0700 @@ -271,8 +271,6 @@ 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 @@ } /* - * 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 @@ 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 @@ 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;
--- a/usr/src/uts/common/fs/zfs/sys/spa_impl.h Fri Jul 04 13:08:26 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/sys/spa_impl.h Mon Jul 07 10:11:14 2008 -0700 @@ -176,6 +176,12 @@ 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
--- a/usr/src/uts/common/fs/zfs/sys/vdev.h Fri Jul 04 13:08:26 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/sys/vdev.h Mon Jul 07 10:11:14 2008 -0700 @@ -56,6 +56,7 @@ 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);
--- a/usr/src/uts/common/fs/zfs/vdev.c Fri Jul 04 13:08:26 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/vdev.c Mon Jul 07 10:11:14 2008 -0700 @@ -2264,3 +2264,35 @@ 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); +}
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c Fri Jul 04 13:08:26 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c Mon Jul 07 10:11:14 2008 -0700 @@ -155,6 +155,30 @@ } /* + * 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 @@ * 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;