--- 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;