From 962d52421236fc9cd61d59b4f18cff3276077da9 Mon Sep 17 00:00:00 2001 From: Tim Chase Date: Mon, 21 Apr 2014 13:22:08 -0500 Subject: [PATCH] Check the dataset type more rigorously when fetching properties. When fetching property values of snapshots, a check against the head dataset type must be performed. Previously, this additional check was performed only when fetching "version", "normalize", "utf8only" or "case". This caused the ZPL properties "acltype", "exec", "devices", "nbmand", "setuid" and "xattr" to be erroneously displayed with meaningless values for snapshots of volumes. It also did not allow for the display of "volsize" of a snapshot of a volume. This patch adds the headcheck flag paramater to zfs_prop_valid_for_type() and zprop_valid_for_type() to indicate the check is being done against a head dataset's type in order that properties valid only for snapshots are handled correctly. This allows the the head check in get_numeric_property() to be performed when fetching a property for a snapshot. Signed-off-by: Tim Chase Signed-off-by: Brian Behlendorf Closes #2265 --- cmd/zfs/zfs_iter.c | 4 ++-- cmd/zfs/zfs_main.c | 6 +++--- include/sys/fs/zfs.h | 2 +- include/zfs_prop.h | 2 +- lib/libzfs/libzfs_dataset.c | 19 +++++++++++++------ lib/libzfs/libzfs_mount.c | 3 ++- lib/libzfs/libzfs_util.c | 2 +- module/zcommon/zfs_prop.c | 6 +++--- module/zcommon/zprop_common.c | 8 +++++++- module/zfs/dsl_prop.c | 2 +- 10 files changed, 34 insertions(+), 20 deletions(-) diff --git a/cmd/zfs/zfs_iter.c b/cmd/zfs/zfs_iter.c index 8892d91f2..eb1d9a54e 100644 --- a/cmd/zfs/zfs_iter.c +++ b/cmd/zfs/zfs_iter.c @@ -328,9 +328,9 @@ zfs_sort(const void *larg, const void *rarg, void *data) rstr = rbuf; } else { lvalid = zfs_prop_valid_for_type(psc->sc_prop, - zfs_get_type(l)); + zfs_get_type(l), B_FALSE); rvalid = zfs_prop_valid_for_type(psc->sc_prop, - zfs_get_type(r)); + zfs_get_type(r), B_FALSE); if (lvalid) (void) zfs_prop_get_numeric(l, psc->sc_prop, diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index d7c1a2a47..7faab4734 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -846,7 +846,7 @@ zfs_do_create(int argc, char **argv) * if the user doesn't want the dataset automatically mounted, * then skip the mount/share step */ - if (zfs_prop_valid_for_type(ZFS_PROP_CANMOUNT, type)) + if (zfs_prop_valid_for_type(ZFS_PROP_CANMOUNT, type, B_FALSE)) canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT); /* @@ -1429,7 +1429,7 @@ get_callback(zfs_handle_t *zhp, void *data) if (pl->pl_all) continue; if (!zfs_prop_valid_for_type(pl->pl_prop, - ZFS_TYPE_DATASET)) { + ZFS_TYPE_DATASET, B_FALSE)) { (void) fprintf(stderr, gettext("No such property '%s'\n"), zfs_prop_to_name(pl->pl_prop)); @@ -1763,7 +1763,7 @@ inherit_recurse_cb(zfs_handle_t *zhp, void *data) * are not valid for this type of dataset. */ if (prop != ZPROP_INVAL && - !zfs_prop_valid_for_type(prop, zfs_get_type(zhp))) + !zfs_prop_valid_for_type(prop, zfs_get_type(zhp), B_FALSE)) return (0); return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0); diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index ae72f834d..7b3ae6cff 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -255,7 +255,7 @@ boolean_t zfs_prop_written(const char *); int zfs_prop_index_to_string(zfs_prop_t, uint64_t, const char **); int zfs_prop_string_to_index(zfs_prop_t, const char *, uint64_t *); uint64_t zfs_prop_random_value(zfs_prop_t, uint64_t seed); -boolean_t zfs_prop_valid_for_type(int, zfs_type_t); +boolean_t zfs_prop_valid_for_type(int, zfs_type_t, boolean_t); /* * Pool property functions shared between libzfs and kernel. diff --git a/include/zfs_prop.h b/include/zfs_prop.h index a63262311..5e7d3f55a 100644 --- a/include/zfs_prop.h +++ b/include/zfs_prop.h @@ -120,7 +120,7 @@ int zprop_index_to_string(int, uint64_t, const char **, zfs_type_t); uint64_t zprop_random_value(int, uint64_t, zfs_type_t); const char *zprop_values(int, zfs_type_t); size_t zprop_width(int, boolean_t *, zfs_type_t); -boolean_t zprop_valid_for_type(int, zfs_type_t); +boolean_t zprop_valid_for_type(int, zfs_type_t, boolean_t); #ifdef __cplusplus } diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 316927c0a..5e43aab2b 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -948,7 +948,7 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, goto error; } - if (!zfs_prop_valid_for_type(prop, type)) { + if (!zfs_prop_valid_for_type(prop, type, B_FALSE)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' does not " "apply to datasets of this type"), propname); @@ -1610,7 +1610,7 @@ zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) /* * Check to see if the value applies to this type */ - if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) + if (!zfs_prop_valid_for_type(prop, zhp->zfs_type, B_FALSE)) return (zfs_error(hdl, EZFS_PROPTYPE, errbuf)); /* @@ -1760,6 +1760,14 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, *source = NULL; + /* + * If the property is being fetched for a snapshot, check whether + * the property is valid for the snapshot's head dataset type. + */ + if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT && + !zfs_prop_valid_for_type(prop, zhp->zfs_head_type, B_TRUE)) + return (-1); + switch (prop) { case ZFS_PROP_ATIME: mntopt_on = MNTOPT_ATIME; @@ -1880,8 +1888,7 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src, case ZFS_PROP_NORMALIZE: case ZFS_PROP_UTF8ONLY: case ZFS_PROP_CASE: - if (!zfs_prop_valid_for_type(prop, zhp->zfs_head_type) || - zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) + if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) return (-1); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) { @@ -2124,7 +2131,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, /* * Check to see if this property applies to our object */ - if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) + if (!zfs_prop_valid_for_type(prop, zhp->zfs_type, B_FALSE)) return (-1); if (received && zfs_prop_readonly(prop)) @@ -2445,7 +2452,7 @@ zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value, /* * Check to see if this property applies to our object */ - if (!zfs_prop_valid_for_type(prop, zhp->zfs_type)) { + if (!zfs_prop_valid_for_type(prop, zhp->zfs_type, B_FALSE)) { return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE, dgettext(TEXT_DOMAIN, "cannot get property '%s'"), zfs_prop_to_name(prop))); diff --git a/lib/libzfs/libzfs_mount.c b/lib/libzfs/libzfs_mount.c index 83396c402..ac3b68226 100644 --- a/lib/libzfs/libzfs_mount.c +++ b/lib/libzfs/libzfs_mount.c @@ -231,7 +231,8 @@ zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen, char sourceloc[ZFS_MAXNAMELEN]; zprop_source_t sourcetype; - if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type)) + if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type, + B_FALSE)) return (B_FALSE); verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen, diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index e99603b49..d029b61e7 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -1531,7 +1531,7 @@ addlist(libzfs_handle_t *hdl, char *propname, zprop_list_t **listp, prop = zprop_name_to_prop(propname, type); - if (prop != ZPROP_INVAL && !zprop_valid_for_type(prop, type)) + if (prop != ZPROP_INVAL && !zprop_valid_for_type(prop, type, B_FALSE)) prop = ZPROP_INVAL; /* diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index dd456b59a..d81ff3bc6 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -391,7 +391,7 @@ zfs_prop_init(void) PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, " | none", "RESERV"); zprop_register_number(ZFS_PROP_VOLSIZE, "volsize", 0, PROP_DEFAULT, - ZFS_TYPE_VOLUME, "", "VOLSIZE"); + ZFS_TYPE_SNAPSHOT | ZFS_TYPE_VOLUME, "", "VOLSIZE"); zprop_register_number(ZFS_PROP_REFQUOTA, "refquota", 0, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM, " | none", "REFQUOTA"); zprop_register_number(ZFS_PROP_REFRESERVATION, "refreservation", 0, @@ -555,9 +555,9 @@ zfs_prop_random_value(zfs_prop_t prop, uint64_t seed) * Returns TRUE if the property applies to any of the given dataset types. */ boolean_t -zfs_prop_valid_for_type(int prop, zfs_type_t types) +zfs_prop_valid_for_type(int prop, zfs_type_t types, boolean_t headcheck) { - return (zprop_valid_for_type(prop, types)); + return (zprop_valid_for_type(prop, types, headcheck)); } zprop_type_t diff --git a/module/zcommon/zprop_common.c b/module/zcommon/zprop_common.c index 6d9f89a98..035f3378d 100644 --- a/module/zcommon/zprop_common.c +++ b/module/zcommon/zprop_common.c @@ -351,9 +351,13 @@ zprop_values(int prop, zfs_type_t type) /* * Returns TRUE if the property applies to any of the given dataset types. + * + * If headcheck is set, the check is being made against the head dataset + * type of a snapshot which requires to return B_TRUE when the property + * is only valid for snapshots. */ boolean_t -zprop_valid_for_type(int prop, zfs_type_t type) +zprop_valid_for_type(int prop, zfs_type_t type, boolean_t headcheck) { zprop_desc_t *prop_tbl; @@ -362,6 +366,8 @@ zprop_valid_for_type(int prop, zfs_type_t type) ASSERT(prop < zprop_get_numprops(type)); prop_tbl = zprop_get_proptable(type); + if (headcheck && prop_tbl[prop].pd_types == ZFS_TYPE_SNAPSHOT) + return (B_TRUE); return ((prop_tbl[prop].pd_types & type) != 0); } diff --git a/module/zfs/dsl_prop.c b/module/zfs/dsl_prop.c index 079ef9742..ded0da991 100644 --- a/module/zfs/dsl_prop.c +++ b/module/zfs/dsl_prop.c @@ -925,7 +925,7 @@ dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj, /* Skip properties not valid for this type. */ if ((flags & DSL_PROP_GET_SNAPSHOT) && prop != ZPROP_INVAL && - !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT)) + !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT, B_FALSE)) continue; /* Skip properties already defined. */