Skip to content

Commit

Permalink
Check large block feature flag on volumes
Browse files Browse the repository at this point in the history
Since ZoL allows large blocks to be used by volumes, unlike upstream
illumos, the feature flag must be checked prior to volume creation.
This is critical because unlike filesystems, volumes will create a
object which uses large blocks as part of the create.  Therefore, it
cannot be safely checked in zfs_check_settable() after the dataset
can been created.

In addition this patch updates the relevant error messages to use
zfs_nicenum() to print the maximum blocksize.

Signed-off-by: Brian Behlendorf <[email protected]>
Closes openzfs#3591
  • Loading branch information
behlendorf committed Aug 28, 2015
1 parent c495fe2 commit 4cb7b9c
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 5 deletions.
2 changes: 1 addition & 1 deletion include/sys/zvol.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 8 additions & 2 deletions lib/libzfs/libzfs_dataset.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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));

Expand Down
3 changes: 2 additions & 1 deletion module/zfs/zfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 &&
Expand Down
26 changes: 25 additions & 1 deletion module/zfs/zvol.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <sys/dsl_dataset.h>
#include <sys/dsl_prop.h>
#include <sys/zap.h>
#include <sys/zfeature.h>
#include <sys/zil_impl.h>
#include <sys/zio.h>
#include <sys/zfs_rlock.h>
Expand Down Expand Up @@ -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))
Expand Down

0 comments on commit 4cb7b9c

Please sign in to comment.