diff --git a/include/sys/zvol.h b/include/sys/zvol.h index 04e0996570c9..898e2352156b 100644 --- a/include/sys/zvol.h +++ b/include/sys/zvol.h @@ -34,7 +34,7 @@ #ifdef _KERNEL extern int zvol_check_volsize(uint64_t volsize, uint64_t blocksize); -extern int zvol_check_volblocksize(uint64_t volblocksize); +extern int zvol_check_volblocksize(const char *name, uint64_t volblocksize); extern int zvol_get_stats(objset_t *os, nvlist_t *nv); extern boolean_t zvol_is_zvol(const char *); extern void zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx); diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 4bb826aca9cf..6b67a73efd8b 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -1059,6 +1059,8 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, case ZFS_PROP_RECORDSIZE: { int maxbs = SPA_MAXBLOCKSIZE; + char buf[64]; + if (zhp != NULL) { maxbs = zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_MAXBLOCKSIZE, NULL); @@ -1069,9 +1071,10 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, */ if (intval < SPA_MINBLOCKSIZE || intval > maxbs || !ISP2(intval)) { + zfs_nicenum(maxbs, buf, sizeof (buf)); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' must be power of 2 from 512B " - "to %uKB"), propname, maxbs >> 10); + "to %s"), propname, buf); (void) zfs_error(hdl, EZFS_BADPROP, errbuf); goto error; } @@ -3210,6 +3213,8 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, /* check for failure */ if (ret != 0) { char parent[ZFS_MAXNAMELEN]; + char buf[64]; + (void) parent_name(path, parent, sizeof (parent)); switch (errno) { @@ -3224,9 +3229,10 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type, return (zfs_error(hdl, EZFS_BADTYPE, errbuf)); case EDOM: + zfs_nicenum(SPA_MAXBLOCKSIZE, buf, sizeof (buf)); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "volume block size must be power of 2 from " - "512B to %uKB"), zfs_max_recordsize >> 10); + "512B to %s"), buf); return (zfs_error(hdl, EZFS_BADPROP, errbuf)); diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index a7bfecea6f18..51382e8b6d10 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -3201,7 +3201,7 @@ zfs_ioc_create(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) volblocksize = zfs_prop_default_numeric( ZFS_PROP_VOLBLOCKSIZE); - if ((error = zvol_check_volblocksize( + if ((error = zvol_check_volblocksize(fsname, volblocksize)) != 0 || (error = zvol_check_volsize(volsize, volblocksize)) != 0) @@ -3841,6 +3841,7 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr) return (SET_ERROR(ENOTSUP)); break; + case ZFS_PROP_VOLBLOCKSIZE: case ZFS_PROP_RECORDSIZE: /* Record sizes above 128k need the feature to be enabled */ if (nvpair_value_uint64(pair, &intval) == 0 && diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index 2b99f44de6a8..3cce00fb686e 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -380,8 +381,31 @@ zvol_set_volsize(const char *name, uint64_t volsize) * Sanity check volume block size. */ int -zvol_check_volblocksize(uint64_t volblocksize) +zvol_check_volblocksize(const char *name, uint64_t volblocksize) { + /* Record sizes above 128k need the feature to be enabled */ + if (volblocksize > SPA_OLD_MAXBLOCKSIZE) { + spa_t *spa; + int error; + + if ((error = spa_open(name, &spa, FTAG)) != 0) + return (error); + + if (!spa_feature_is_enabled(spa, SPA_FEATURE_LARGE_BLOCKS)) { + spa_close(spa, FTAG); + return (SET_ERROR(ENOTSUP)); + } + + /* + * We don't allow setting the property above 1MB, + * unless the tunable has been changed. + */ + if (volblocksize > zfs_max_recordsize) + return (SET_ERROR(EDOM)); + + spa_close(spa, FTAG); + } + if (volblocksize < SPA_MINBLOCKSIZE || volblocksize > SPA_MAXBLOCKSIZE || !ISP2(volblocksize))