summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/truss/codes.c8
-rw-r--r--usr/src/cmd/zfs/Makefile9
-rw-r--r--usr/src/cmd/zfs/zfs_iter.c113
-rw-r--r--usr/src/cmd/zfs/zfs_iter.h5
-rw-r--r--usr/src/cmd/zfs/zfs_main.c706
-rw-r--r--usr/src/cmd/zoneadm/Makefile2
-rw-r--r--usr/src/cmd/zoneadm/zfs.c55
-rw-r--r--usr/src/cmd/zoneadmd/vplat.c3
-rw-r--r--usr/src/cmd/zpool/zpool_main.c42
-rw-r--r--usr/src/common/zfs/zfs_prop.c348
-rw-r--r--usr/src/common/zfs/zfs_prop.h10
-rw-r--r--usr/src/lib/libzfs/common/libzfs.h59
-rw-r--r--usr/src/lib/libzfs/common/libzfs_changelist.c8
-rw-r--r--usr/src/lib/libzfs/common/libzfs_config.c59
-rw-r--r--usr/src/lib/libzfs/common/libzfs_dataset.c1344
-rw-r--r--usr/src/lib/libzfs/common/libzfs_graph.c13
-rw-r--r--usr/src/lib/libzfs/common/libzfs_impl.h17
-rw-r--r--usr/src/lib/libzfs/common/libzfs_import.c47
-rw-r--r--usr/src/lib/libzfs/common/libzfs_mount.c130
-rw-r--r--usr/src/lib/libzfs/common/libzfs_pool.c196
-rw-r--r--usr/src/lib/libzfs/common/libzfs_util.c100
-rw-r--r--usr/src/lib/libzfs/common/mapfile-vers8
-rw-r--r--usr/src/uts/common/fs/zfs/dmu.c20
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_prop.c38
-rw-r--r--usr/src/uts/common/fs/zfs/sys/spa.h4
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_acl.h10
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h48
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zvol.h71
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_acl.c14
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ctldir.c4
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ioctl.c553
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vfsops.c2
-rw-r--r--usr/src/uts/common/fs/zfs/zvol.c79
-rw-r--r--usr/src/uts/common/sys/fs/zfs.h17
34 files changed, 2583 insertions, 1559 deletions
diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c
index 66f9a00daa..1963879b94 100644
--- a/usr/src/cmd/truss/codes.c
+++ b/usr/src/cmd/truss/codes.c
@@ -901,14 +901,6 @@ const struct ioc {
"zfs_cmd_t" },
{ (uint_t)ZFS_IOC_SET_PROP, "ZFS_IOC_SET_PROP",
"zfs_cmd_t" },
- { (uint_t)ZFS_IOC_SET_QUOTA, "ZFS_IOC_SET_QUOTA",
- "zfs_cmd_t" },
- { (uint_t)ZFS_IOC_SET_RESERVATION, "ZFS_IOC_SET_RESERVATION",
- "zfs_cmd_t" },
- { (uint_t)ZFS_IOC_SET_VOLSIZE, "ZFS_IOC_SET_VOLSIZE",
- "zfs_cmd_t" },
- { (uint_t)ZFS_IOC_SET_VOLBLOCKSIZE, "ZFS_IOC_SET_VOLBLOCKSIZE",
- "zfs_cmd_t" },
{ (uint_t)ZFS_IOC_CREATE_MINOR, "ZFS_IOC_CREATE_MINOR",
"zfs_cmd_t" },
{ (uint_t)ZFS_IOC_REMOVE_MINOR, "ZFS_IOC_REMOVE_MINOR",
diff --git a/usr/src/cmd/zfs/Makefile b/usr/src/cmd/zfs/Makefile
index 3a80b1c77e..9b80822041 100644
--- a/usr/src/cmd/zfs/Makefile
+++ b/usr/src/cmd/zfs/Makefile
@@ -2,9 +2,8 @@
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -39,7 +38,7 @@ LINKPROGS= mount umount
ROOTETCFSTYPE= $(ROOTETC)/fs/$(FSTYPE)
USRLIBFSTYPE= $(ROOTLIB)/fs/$(FSTYPE)
-LDLIBS += -lzfs -luutil -lumem
+LDLIBS += -lzfs -luutil -lumem -lnvpair
C99MODE= -xc99=%all
C99LMODE= -Xc99=%all
diff --git a/usr/src/cmd/zfs/zfs_iter.c b/usr/src/cmd/zfs/zfs_iter.c
index 814a165393..c2d4260d8f 100644
--- a/usr/src/cmd/zfs/zfs_iter.c
+++ b/usr/src/cmd/zfs/zfs_iter.c
@@ -59,6 +59,7 @@ typedef struct callback_data {
int cb_recurse;
zfs_type_t cb_types;
zfs_sort_column_t *cb_sortcol;
+ zfs_proplist_t **cb_proplist;
} callback_data_t;
uu_avl_pool_t *avl_pool;
@@ -84,6 +85,11 @@ zfs_callback(zfs_handle_t *zhp, void *data)
uu_avl_node_init(node, &node->zn_avlnode, avl_pool);
if (uu_avl_find(cb->cb_avl, node, cb->cb_sortcol,
&idx) == NULL) {
+ if (cb->cb_proplist &&
+ zfs_expand_proplist(zhp, cb->cb_proplist) != 0) {
+ free(node);
+ return (-1);
+ }
uu_avl_insert(cb->cb_avl, node, idx);
dontclose = 1;
} else {
@@ -105,17 +111,25 @@ zfs_callback(zfs_handle_t *zhp, void *data)
return (0);
}
-void
-zfs_add_sort_column(zfs_sort_column_t **sc, zfs_prop_t prop,
+int
+zfs_add_sort_column(zfs_sort_column_t **sc, const char *name,
boolean_t reverse)
{
zfs_sort_column_t *col;
+ zfs_prop_t prop;
+
+ if ((prop = zfs_name_to_prop(name)) == ZFS_PROP_INVAL &&
+ !zfs_prop_user(name))
+ return (-1);
col = safe_malloc(sizeof (zfs_sort_column_t));
col->sc_prop = prop;
col->sc_reverse = reverse;
- col->sc_next = NULL;
+ if (prop == ZFS_PROP_INVAL) {
+ col->sc_user_prop = safe_malloc(strlen(name) + 1);
+ (void) strcpy(col->sc_user_prop, name);
+ }
if (*sc == NULL) {
col->sc_last = col;
@@ -124,6 +138,8 @@ zfs_add_sort_column(zfs_sort_column_t **sc, zfs_prop_t prop,
(*sc)->sc_last->sc_next = col;
(*sc)->sc_last = col;
}
+
+ return (0);
}
void
@@ -133,6 +149,7 @@ zfs_free_sort_columns(zfs_sort_column_t *sc)
while (sc != NULL) {
col = sc->sc_next;
+ free(sc->sc_user_prop);
free(sc);
sc = col;
}
@@ -214,48 +231,72 @@ zfs_sort(const void *larg, const void *rarg, void *data)
zfs_sort_column_t *psc;
for (psc = sc; psc != NULL; psc = psc->sc_next) {
- char lstr[ZFS_MAXPROPLEN], rstr[ZFS_MAXPROPLEN];
+ char lbuf[ZFS_MAXPROPLEN], rbuf[ZFS_MAXPROPLEN];
+ char *lstr, *rstr;
uint64_t lnum, rnum;
- int lvalid, rvalid;
+ boolean_t lvalid, rvalid;
int ret = 0;
- if (zfs_prop_is_string(psc->sc_prop)) {
- lvalid = zfs_prop_get(l, psc->sc_prop, lstr,
- sizeof (lstr), NULL, NULL, 0, B_TRUE);
- rvalid = zfs_prop_get(r, psc->sc_prop, rstr,
- sizeof (rstr), NULL, NULL, 0, B_TRUE);
-
- if ((lvalid == -1) && (rvalid == -1))
- continue;
- if (lvalid == -1)
- return (1);
- else if (rvalid == -1)
- return (-1);
-
- ret = strcmp(lstr, rstr);
+ /*
+ * We group the checks below the generic code. If 'lstr' and
+ * 'rstr' are non-NULL, then we do a string based comparison.
+ * Otherwise, we compare 'lnum' and 'rnum'.
+ */
+ lstr = rstr = NULL;
+ if (psc->sc_prop == ZFS_PROP_INVAL) {
+ nvlist_t *luser, *ruser;
+ nvlist_t *lval, *rval;
+
+ luser = zfs_get_user_props(l);
+ ruser = zfs_get_user_props(r);
+
+ lvalid = (nvlist_lookup_nvlist(luser,
+ psc->sc_user_prop, &lval) == 0);
+ rvalid = (nvlist_lookup_nvlist(ruser,
+ psc->sc_user_prop, &rval) == 0);
+
+ if (lvalid)
+ verify(nvlist_lookup_string(lval,
+ ZFS_PROP_VALUE, &lstr) == 0);
+ if (rvalid)
+ verify(nvlist_lookup_string(rval,
+ ZFS_PROP_VALUE, &rstr) == 0);
+
+ } else if (zfs_prop_is_string(psc->sc_prop)) {
+ lvalid = (zfs_prop_get(l, psc->sc_prop, lbuf,
+ sizeof (lbuf), NULL, NULL, 0, B_TRUE) == 0);
+ rvalid = (zfs_prop_get(r, psc->sc_prop, rbuf,
+ sizeof (rbuf), NULL, NULL, 0, B_TRUE) == 0);
+
+ lstr = lbuf;
+ rstr = rbuf;
} else {
lvalid = zfs_prop_valid_for_type(psc->sc_prop,
zfs_get_type(l));
rvalid = zfs_prop_valid_for_type(psc->sc_prop,
zfs_get_type(r));
- if (!lvalid && !rvalid)
- continue;
- else if (!lvalid)
- return (1);
- else if (!rvalid)
- return (-1);
+ if (lvalid)
+ (void) zfs_prop_get_numeric(l, psc->sc_prop,
+ &lnum, NULL, NULL, 0);
+ if (rvalid)
+ (void) zfs_prop_get_numeric(r, psc->sc_prop,
+ &rnum, NULL, NULL, 0);
+ }
- (void) zfs_prop_get_numeric(l, psc->sc_prop, &lnum,
- NULL, NULL, 0);
- (void) zfs_prop_get_numeric(r, psc->sc_prop, &rnum,
- NULL, NULL, 0);
+ if (!lvalid && !rvalid)
+ continue;
+ else if (!lvalid)
+ return (1);
+ else if (!rvalid)
+ return (-1);
- if (lnum < rnum)
- ret = -1;
- else if (lnum > rnum)
- ret = 1;
- }
+ if (lstr)
+ ret = strcmp(lstr, rstr);
+ if (lnum < rnum)
+ ret = -1;
+ else if (lnum > rnum)
+ ret = 1;
if (ret != 0) {
if (psc->sc_reverse == B_TRUE)
@@ -269,7 +310,8 @@ zfs_sort(const void *larg, const void *rarg, void *data)
int
zfs_for_each(int argc, char **argv, boolean_t recurse, zfs_type_t types,
- zfs_sort_column_t *sortcol, zfs_iter_f callback, void *data)
+ zfs_sort_column_t *sortcol, zfs_proplist_t **proplist, zfs_iter_f callback,
+ void *data)
{
callback_data_t cb;
int ret = 0;
@@ -287,6 +329,7 @@ zfs_for_each(int argc, char **argv, boolean_t recurse, zfs_type_t types,
cb.cb_sortcol = sortcol;
cb.cb_recurse = recurse;
+ cb.cb_proplist = proplist;
cb.cb_types = types;
if ((cb.cb_avl = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL) {
(void) fprintf(stderr,
diff --git a/usr/src/cmd/zfs/zfs_iter.h b/usr/src/cmd/zfs/zfs_iter.h
index de734e8d4e..d5c735d604 100644
--- a/usr/src/cmd/zfs/zfs_iter.h
+++ b/usr/src/cmd/zfs/zfs_iter.h
@@ -36,12 +36,13 @@ typedef struct zfs_sort_column {
struct zfs_sort_column *sc_next;
struct zfs_sort_column *sc_last;
zfs_prop_t sc_prop;
+ char *sc_user_prop;
boolean_t sc_reverse;
} zfs_sort_column_t;
int zfs_for_each(int, char **, boolean_t, zfs_type_t, zfs_sort_column_t *,
- zfs_iter_f, void *);
-void zfs_add_sort_column(zfs_sort_column_t **, zfs_prop_t, boolean_t);
+ zfs_proplist_t **, zfs_iter_f, void *);
+int zfs_add_sort_column(zfs_sort_column_t **, const char *, boolean_t);
void zfs_free_sort_columns(zfs_sort_column_t *);
#ifdef __cplusplus
diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c
index ad9f6e8b07..eb5d4e4b75 100644
--- a/usr/src/cmd/zfs/zfs_main.c
+++ b/usr/src/cmd/zfs/zfs_main.c
@@ -26,6 +26,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
#include <assert.h>
+#include <ctype.h>
#include <errno.h>
#include <libgen.h>
#include <libintl.h>
@@ -161,8 +162,10 @@ get_usage(zfs_help_t idx)
case HELP_CLONE:
return (gettext("\tclone <snapshot> <filesystem|volume>\n"));
case HELP_CREATE:
- return (gettext("\tcreate <filesystem>\n"
- "\tcreate [-s] [-b blocksize] -V <size> <volume>\n"));
+ return (gettext("\tcreate [[-o property=value] ... ] "
+ "<filesystem>\n"
+ "\tcreate [-s] [-b blocksize] [[-o property=value] ...]\n"
+ "\t -V <size> <volume>\n"));
case HELP_DESTROY:
return (gettext("\tdestroy [-rRf] "
"<filesystem|volume|snapshot>\n"));
@@ -170,7 +173,7 @@ get_usage(zfs_help_t idx)
return (gettext("\tget [-rHp] [-o field[,field]...] "
"[-s source[,source]...]\n"
"\t <all | property[,property]...> "
- "<filesystem|volume|snapshot> ...\n"));
+ "[filesystem|volume|snapshot] ...\n"));
case HELP_INHERIT:
return (gettext("\tinherit [-r] <property> "
"<filesystem|volume> ...\n"));
@@ -302,6 +305,8 @@ usage(boolean_t requested)
}
(void) fprintf(fp, gettext("\nSizes are specified in bytes "
"with standard units such as K, M, G, etc.\n"));
+ (void) fprintf(fp, gettext("\n\nUser-defined properties can "
+ "be specified by using a name containing a colon (:).\n"));
} else {
/*
* TRANSLATION NOTE:
@@ -312,6 +317,14 @@ usage(boolean_t requested)
gettext("\nFor the property list, run: zfs set|get\n"));
}
+ /*
+ * See comments at end of main().
+ */
+ if (getenv("ZFS_ABORT") != NULL) {
+ (void) printf("dumping core by request\n");
+ abort();
+ }
+
exit(requested ? 0 : 2);
}
@@ -357,7 +370,7 @@ zfs_do_clone(int argc, char **argv)
return (1);
/* pass to libzfs */
- ret = zfs_clone(zhp, argv[2]);
+ ret = zfs_clone(zhp, argv[2], NULL);
/* create the mountpoint if necessary */
if (ret == 0) {
@@ -375,8 +388,8 @@ zfs_do_clone(int argc, char **argv)
}
/*
- * zfs create fs
- * zfs create [-s] [-b blocksize] -V vol size
+ * zfs create [-o prop=value] ... fs
+ * zfs create [-s] [-b blocksize] [-o prop=value] ... -V vol size
*
* Create a new dataset. This command can be used to create filesystems
* and volumes. Snapshot creation is handled by 'zfs snapshot'.
@@ -390,22 +403,79 @@ static int
zfs_do_create(int argc, char **argv)
{
zfs_type_t type = ZFS_TYPE_FILESYSTEM;
- zfs_handle_t *zhp;
- char *size = NULL;
- char *blocksize = NULL;
+ zfs_handle_t *zhp = NULL;
+ uint64_t volsize;
int c;
boolean_t noreserve = B_FALSE;
- int ret;
+ int ret = 1;
+ nvlist_t *props = NULL;
+ uint64_t intval;
+ char *propname;
+ char *propval, *strval;
+
+ if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
+ (void) fprintf(stderr, gettext("internal error: "
+ "out of memory\n"));
+ return (1);
+ }
/* check options */
- while ((c = getopt(argc, argv, ":V:b:s")) != -1) {
+ while ((c = getopt(argc, argv, ":V:b:so:")) != -1) {
switch (c) {
case 'V':
type = ZFS_TYPE_VOLUME;
- size = optarg;
+ if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) {
+ (void) fprintf(stderr, gettext("bad volume "
+ "size '%s': %s\n"), optarg,
+ libzfs_error_description(g_zfs));
+ goto error;
+ }
+
+ if (nvlist_add_uint64(props,
+ zfs_prop_to_name(ZFS_PROP_VOLSIZE),
+ intval) != 0) {
+ (void) fprintf(stderr, gettext("internal "
+ "error: out of memory\n"));
+ goto error;
+ }
+ volsize = intval;
break;
case 'b':
- blocksize = optarg;
+ if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) {
+ (void) fprintf(stderr, gettext("bad volume "
+ "block size '%s': %s\n"), optarg,
+ libzfs_error_description(g_zfs));
+ goto error;
+ }
+
+ if (nvlist_add_uint64(props,
+ zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+ intval) != 0) {
+ (void) fprintf(stderr, gettext("internal "
+ "error: out of memory\n"));
+ goto error;
+ }
+ break;
+ case 'o':
+ propname = optarg;
+ if ((propval = strchr(propname, '=')) == NULL) {
+ (void) fprintf(stderr, gettext("missing "
+ "'=' for -o option\n"));
+ goto error;
+ }
+ *propval = '\0';
+ propval++;
+ if (nvlist_lookup_string(props, propname,
+ &strval) == 0) {
+ (void) fprintf(stderr, gettext("property '%s' "
+ "specified multiple times\n"), propname);
+ goto error;
+ }
+ if (nvlist_add_string(props, propname, propval) != 0) {
+ (void) fprintf(stderr, gettext("internal "
+ "error: out of memory\n"));
+ goto error;
+ }
break;
case 's':
noreserve = B_TRUE;
@@ -413,19 +483,19 @@ zfs_do_create(int argc, char **argv)
case ':':
(void) fprintf(stderr, gettext("missing size "
"argument\n"));
- usage(B_FALSE);
+ goto badusage;
break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
- usage(B_FALSE);
+ goto badusage;
}
}
if (noreserve && type != ZFS_TYPE_VOLUME) {
(void) fprintf(stderr, gettext("'-s' can only be used when "
"creating a volume\n"));
- usage(B_FALSE);
+ goto badusage;
}
argc -= optind;
@@ -435,33 +505,32 @@ zfs_do_create(int argc, char **argv)
if (argc == 0) {
(void) fprintf(stderr, gettext("missing %s argument\n"),
zfs_type_to_name(type));
- usage(B_FALSE);
+ goto badusage;
}
if (argc > 1) {
(void) fprintf(stderr, gettext("too many arguments\n"));
- usage(B_FALSE);
+ goto badusage;
+ }
+
+ if (type == ZFS_TYPE_VOLUME && !noreserve &&
+ nvlist_lookup_string(props, zfs_prop_to_name(ZFS_PROP_RESERVATION),
+ &strval) != 0) {
+ if (nvlist_add_uint64(props,
+ zfs_prop_to_name(ZFS_PROP_RESERVATION),
+ volsize) != 0) {
+ (void) fprintf(stderr, gettext("internal "
+ "error: out of memory\n"));
+ nvlist_free(props);
+ return (1);
+ }
}
/* pass to libzfs */
- if (zfs_create(g_zfs, argv[0], type, size, blocksize) != 0)
- return (1);
+ if (zfs_create(g_zfs, argv[0], type, props) != 0)
+ goto error;
if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_ANY)) == NULL)
- return (1);
-
- /*
- * Volume handling. By default, we try to create a reservation of equal
- * size for the volume. If we can't do this, then destroy the dataset
- * and report an error.
- */
- if (type == ZFS_TYPE_VOLUME && !noreserve) {
- if (zfs_prop_set(zhp, ZFS_PROP_RESERVATION, size) != 0) {
- (void) fprintf(stderr, gettext("use '-s' to create a "
- "volume without a matching reservation\n"));
- (void) zfs_destroy(zhp);
- return (1);
- }
- }
+ goto error;
/*
* Mount and/or share the new filesystem as appropriate. We provide a
@@ -480,8 +549,15 @@ zfs_do_create(int argc, char **argv)
ret = 0;
}
- zfs_close(zhp);
+error:
+ if (zhp)
+ zfs_close(zhp);
+ nvlist_free(props);
return (ret);
+badusage:
+ nvlist_free(props);
+ usage(B_FALSE);
+ return (2);
}
/*
@@ -765,11 +841,11 @@ zfs_do_destroy(int argc, char **argv)
typedef struct get_cbdata {
int cb_sources;
int cb_columns[4];
- int cb_nprop;
+ int cb_colwidths[5];
boolean_t cb_scripted;
boolean_t cb_literal;
- boolean_t cb_isall;
- zfs_prop_t cb_prop[ZFS_NPROP_ALL];
+ boolean_t cb_first;
+ zfs_proplist_t *cb_proplist;
} get_cbdata_t;
#define GET_COL_NAME 1
@@ -778,15 +854,110 @@ typedef struct get_cbdata {
#define GET_COL_SOURCE 4
/*
+ * Print the column headers for 'zfs get'.
+ */
+static void
+print_get_headers(get_cbdata_t *cbp)
+{
+ zfs_proplist_t *pl = cbp->cb_proplist;
+ int i;
+ char *title;
+ size_t len;
+
+ cbp->cb_first = B_FALSE;
+ if (cbp->cb_scripted)
+ return;
+
+ /*
+ * Start with the length of the column headers.
+ */
+ cbp->cb_colwidths[GET_COL_NAME] = strlen(gettext("NAME"));
+ cbp->cb_colwidths[GET_COL_PROPERTY] = strlen(gettext("PROPERTY"));
+ cbp->cb_colwidths[GET_COL_VALUE] = strlen(gettext("VALUE"));
+ cbp->cb_colwidths[GET_COL_SOURCE] = strlen(gettext("SOURCE"));
+
+ /*
+ * Go through and calculate the widths for each column. For the
+ * 'source' column, we kludge it up by taking the worst-case scenario of
+ * inheriting from the longest name. This is acceptable because in the
+ * majority of cases 'SOURCE' is the last column displayed, and we don't
+ * use the width anyway. Note that the 'VALUE' column can be oversized,
+ * if the name of the property is much longer the any values we find.
+ */
+ for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
+ /*
+ * 'PROPERTY' column
+ */
+ if (pl->pl_prop != ZFS_PROP_INVAL) {
+ len = strlen(zfs_prop_to_name(pl->pl_prop));
+ if (len > cbp->cb_colwidths[GET_COL_PROPERTY])
+ cbp->cb_colwidths[GET_COL_PROPERTY] = len;
+ } else {
+ len = strlen(pl->pl_user_prop);
+ if (len > cbp->cb_colwidths[GET_COL_PROPERTY])
+ cbp->cb_colwidths[GET_COL_PROPERTY] = len;
+ }
+
+ /*
+ * 'VALUE' column
+ */
+ if ((pl->pl_prop != ZFS_PROP_NAME || !pl->pl_all) &&
+ pl->pl_width > cbp->cb_colwidths[GET_COL_VALUE])
+ cbp->cb_colwidths[GET_COL_VALUE] = pl->pl_width;
+
+ /*
+ * 'NAME' and 'SOURCE' columns
+ */
+ if (pl->pl_prop == ZFS_PROP_NAME &&
+ pl->pl_width > cbp->cb_colwidths[GET_COL_NAME]) {
+ cbp->cb_colwidths[GET_COL_NAME] = pl->pl_width;
+ cbp->cb_colwidths[GET_COL_SOURCE] = pl->pl_width +
+ strlen(gettext("inherited from"));
+ }
+ }
+
+ /*
+ * Now go through and print the headers.
+ */
+ for (i = 0; i < 4; i++) {
+ switch (cbp->cb_columns[i]) {
+ case GET_COL_NAME:
+ title = gettext("NAME");
+ break;
+ case GET_COL_PROPERTY:
+ title = gettext("PROPERTY");
+ break;
+ case GET_COL_VALUE:
+ title = gettext("VALUE");
+ break;
+ case GET_COL_SOURCE:
+ title = gettext("SOURCE");
+ break;
+ default:
+ title = NULL;
+ }
+
+ if (title != NULL) {
+ if (i == 3 || cbp->cb_columns[i + 1] == 0)
+ (void) printf("%s", title);
+ else
+ (void) printf("%-*s ",
+ cbp->cb_colwidths[cbp->cb_columns[i]],
+ title);
+ }
+ }
+ (void) printf("\n");
+}
+
+/*
* Display a single line of output, according to the settings in the callback
* structure.
*/
static void
-print_one_property(zfs_handle_t *zhp, get_cbdata_t *cbp, zfs_prop_t prop,
+print_one_property(zfs_handle_t *zhp, get_cbdata_t *cbp, const char *propname,
const char *value, zfs_source_t sourcetype, const char *source)
{
int i;
- int width;
const char *str;
char buf[128];
@@ -796,25 +967,24 @@ print_one_property(zfs_handle_t *zhp, get_cbdata_t *cbp, zfs_prop_t prop,
if ((sourcetype & cbp->cb_sources) == 0)
return;
+ if (cbp->cb_first)
+ print_get_headers(cbp);
+
for (i = 0; i < 4; i++) {
switch (cbp->cb_columns[i]) {
case GET_COL_NAME:
- width = 15;
str = zfs_get_name(zhp);
break;
case GET_COL_PROPERTY:
- width = 13;
- str = zfs_prop_to_name(prop);
+ str = propname;
break;
case GET_COL_VALUE:
- width = 25;
str = value;
break;
case GET_COL_SOURCE:
- width = 15;
switch (sourcetype) {
case ZFS_SRC_NONE:
str = "-";
@@ -849,7 +1019,9 @@ print_one_property(zfs_handle_t *zhp, get_cbdata_t *cbp, zfs_prop_t prop,
else if (cbp->cb_scripted)
(void) printf("%s\t", str);
else
- (void) printf("%-*s ", width, str);
+ (void) printf("%-*s ",
+ cbp->cb_colwidths[cbp->cb_columns[i]],
+ str);
}
@@ -866,20 +1038,62 @@ get_callback(zfs_handle_t *zhp, void *data)
zfs_source_t sourcetype;
char source[ZFS_MAXNAMELEN];
get_cbdata_t *cbp = data;
- int i;
+ nvlist_t *userprop = zfs_get_user_props(zhp);
+ zfs_proplist_t *pl = cbp->cb_proplist;
+ nvlist_t *propval;
+ char *strval;
+ char *sourceval;
- for (i = 0; i < cbp->cb_nprop; i++) {
- if (zfs_prop_get(zhp, cbp->cb_prop[i], buf,
- sizeof (buf), &sourcetype, source, sizeof (source),
- cbp->cb_literal) != 0) {
- if (cbp->cb_isall)
- continue;
- (void) strlcpy(buf, "-", sizeof (buf));
- sourcetype = ZFS_SRC_NONE;
- }
+ for (; pl != NULL; pl = pl->pl_next) {
+ /*
+ * Skip the special fake placeholder. This will also skip over
+ * the name property when 'all' is specified.
+ */
+ if (pl->pl_prop == ZFS_PROP_NAME &&
+ pl == cbp->cb_proplist)
+ continue;
+
+ if (pl->pl_prop != ZFS_PROP_INVAL) {
+ if (zfs_prop_get(zhp, pl->pl_prop, buf,
+ sizeof (buf), &sourcetype, source,
+ sizeof (source),
+ cbp->cb_literal) != 0) {
+ if (pl->pl_all)
+ continue;
+ sourcetype = ZFS_SRC_NONE;
+ (void) strlcpy(buf, "-", sizeof (buf));
+ }
- print_one_property(zhp, cbp, cbp->cb_prop[i],
- buf, sourcetype, source);
+ print_one_property(zhp, cbp,
+ zfs_prop_to_name(pl->pl_prop),
+ buf, sourcetype, source);
+ } else {
+ if (nvlist_lookup_nvlist(userprop,
+ pl->pl_user_prop, &propval) != 0) {
+ if (pl->pl_all)
+ continue;
+ sourcetype = ZFS_SRC_NONE;
+ strval = "-";
+ } else {
+ verify(nvlist_lookup_string(propval,
+ ZFS_PROP_VALUE, &strval) == 0);
+ verify(nvlist_lookup_string(propval,
+ ZFS_PROP_SOURCE, &sourceval) == 0);
+
+ if (strcmp(sourceval,
+ zfs_get_name(zhp)) == 0) {
+ sourcetype = ZFS_SRC_LOCAL;
+ } else {
+ sourcetype = ZFS_SRC_INHERITED;
+ (void) strlcpy(source,
+ sourceval, sizeof (source));
+ }
+ }
+
+ print_one_property(zhp, cbp,
+ pl->pl_user_prop, strval, sourcetype,
+ source);
+ }
}
return (0);
@@ -890,10 +1104,10 @@ zfs_do_get(int argc, char **argv)
{
get_cbdata_t cb = { 0 };
boolean_t recurse = B_FALSE;
- int c;
- char *value, *fields, *badopt;
- int i;
+ int i, c;
+ char *value, *fields;
int ret;
+ zfs_proplist_t fake_name = { 0 };
/*
* Set up default columns and sources.
@@ -1014,62 +1228,39 @@ zfs_do_get(int argc, char **argv)
fields = argv[0];
- /*
- * If the user specifies 'all', the behavior of 'zfs get' is slightly
- * different, because we don't show properties which don't apply to the
- * given dataset.
- */
- if (strcmp(fields, "all") == 0)
- cb.cb_isall = B_TRUE;
-
- if ((ret = zfs_get_proplist(fields, cb.cb_prop, ZFS_NPROP_ALL,
- &cb.cb_nprop, &badopt)) != 0) {
- if (ret == EINVAL)
- (void) fprintf(stderr, gettext("invalid property "
- "'%s'\n"), badopt);
- else
- (void) fprintf(stderr, gettext("too many properties "
- "specified\n"));
+ if (zfs_get_proplist(g_zfs, fields, &cb.cb_proplist) != 0)
usage(B_FALSE);
- }
argc--;
argv++;
- /* check for at least one dataset name */
- if (argc < 1) {
- (void) fprintf(stderr, gettext("missing dataset argument\n"));
- usage(B_FALSE);
- }
-
/*
- * Print out any headers
+ * As part of zfs_expand_proplist(), we keep track of the maximum column
+ * width for each property. For the 'NAME' (and 'SOURCE') columns, we
+ * need to know the maximum name length. However, the user likely did
+ * not specify 'name' as one of the properties to fetch, so we need to
+ * make sure we always include at least this property for
+ * print_get_headers() to work properly.
*/
- if (!cb.cb_scripted) {
- int i;
- for (i = 0; i < 4; i++) {
- switch (cb.cb_columns[i]) {
- case GET_COL_NAME:
- (void) printf("%-15s ", "NAME");
- break;
- case GET_COL_PROPERTY:
- (void) printf("%-13s ", "PROPERTY");
- break;
- case GET_COL_VALUE:
- (void) printf("%-25s ", "VALUE");
- break;
- case GET_COL_SOURCE:
- (void) printf("%s", "SOURCE");
- break;
- }
- }
- (void) printf("\n");
+ if (cb.cb_proplist != NULL) {
+ fake_name.pl_prop = ZFS_PROP_NAME;
+ fake_name.pl_width = strlen(gettext("NAME"));
+ fake_name.pl_next = cb.cb_proplist;
+ cb.cb_proplist = &fake_name;
}
+ cb.cb_first = B_TRUE;
+
/* run for each object */
- return (zfs_for_each(argc, argv, recurse, ZFS_TYPE_ANY, NULL,
- get_callback, &cb));
+ ret = zfs_for_each(argc, argv, recurse, ZFS_TYPE_ANY, NULL,
+ &cb.cb_proplist, get_callback, &cb);
+
+ if (cb.cb_proplist == &fake_name)
+ zfs_free_proplist(fake_name.pl_next);
+ else
+ zfs_free_proplist(cb.cb_proplist);
+ return (ret);
}
/*
@@ -1086,9 +1277,7 @@ zfs_do_get(int argc, char **argv)
static int
inherit_callback(zfs_handle_t *zhp, void *data)
{
- zfs_prop_t prop = (zfs_prop_t)data;
-
- return (zfs_prop_inherit(zhp, prop) != 0);
+ return (zfs_prop_inherit(zhp, data) != 0);
}
static int
@@ -1127,33 +1316,35 @@ zfs_do_inherit(int argc, char **argv)
}
propname = argv[0];
+ argc--;
+ argv++;
- /*
- * Get and validate the property before iterating over the datasets. We
- * do this now so as to avoid printing out an error message for each and
- * every dataset.
- */
- if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) {
- (void) fprintf(stderr, gettext("invalid property '%s'\n"),
+ if ((prop = zfs_name_to_prop(propname)) != ZFS_PROP_INVAL) {
+ if (zfs_prop_readonly(prop)) {
+ (void) fprintf(stderr, gettext(
+ "%s property is read-only\n"),
+ propname);
+ return (1);
+ }
+ if (!zfs_prop_inheritable(prop)) {
+ (void) fprintf(stderr, gettext("'%s' property cannot "
+ "be inherited\n"), propname);
+ if (prop == ZFS_PROP_QUOTA ||
+ prop == ZFS_PROP_RESERVATION)
+ (void) fprintf(stderr, gettext("use 'zfs set "
+ "%s=none' to clear\n"), propname);
+ return (1);
+ }
+ } else if (!zfs_prop_user(propname)) {
+ (void) fprintf(stderr, gettext(
+ "invalid property '%s'\n"),
propname);
usage(B_FALSE);
}
- if (zfs_prop_readonly(prop)) {
- (void) fprintf(stderr, gettext("%s property is read-only\n"),
- propname);
- return (1);
- }
- if (!zfs_prop_inheritable(prop)) {
- (void) fprintf(stderr, gettext("%s property cannot be "
- "inherited\n"), propname);
- (void) fprintf(stderr, gettext("use 'zfs set %s=none' to "
- "clear\n"), propname);
- return (1);
- }
- return (zfs_for_each(argc - 1, argv + 1, recurse,
- ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, NULL,
- inherit_callback, (void *)prop));
+ return (zfs_for_each(argc, argv, recurse,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, NULL, NULL,
+ inherit_callback, propname));
}
/*
@@ -1175,26 +1366,45 @@ zfs_do_inherit(int argc, char **argv)
typedef struct list_cbdata {
boolean_t cb_first;
boolean_t cb_scripted;
- zfs_prop_t cb_fields[ZFS_NPROP_ALL];
- int cb_fieldcount;
+ zfs_proplist_t *cb_proplist;
} list_cbdata_t;
/*
* Given a list of columns to display, output appropriate headers for each one.
*/
static void
-print_header(zfs_prop_t *fields, size_t count)
+print_header(zfs_proplist_t *pl)
{
+ char headerbuf[ZFS_MAXPROPLEN];
+ const char *header;
int i;
+ boolean_t first = B_TRUE;
+ boolean_t right_justify;
- for (i = 0; i < count; i++) {
- if (i != 0)
+ for (; pl != NULL; pl = pl->pl_next) {
+ if (!first) {
(void) printf(" ");
- if (i == count - 1)
- (void) printf("%s", zfs_prop_column_name(fields[i]));
- else /* LINTED - format specifier */
- (void) printf(zfs_prop_column_format(fields[i]),
- zfs_prop_column_name(fields[i]));
+ } else {
+ first = B_FALSE;
+ }
+
+ right_justify = B_FALSE;
+ if (pl->pl_prop != ZFS_PROP_INVAL) {
+ header = zfs_prop_column_name(pl->pl_prop);
+ right_justify = zfs_prop_align_right(pl->pl_prop);
+ } else {
+ for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
+ headerbuf[i] = toupper(pl->pl_user_prop[i]);
+ headerbuf[i] = '\0';
+ header = headerbuf;
+ }
+
+ if (pl->pl_next == NULL && !right_justify)
+ (void) printf("%s", header);
+ else if (right_justify)
+ (void) printf("%*s", pl->pl_width, header);
+ else
+ (void) printf("%-*s", pl->pl_width, header);
}
(void) printf("\n");
@@ -1205,34 +1415,57 @@ print_header(zfs_prop_t *fields, size_t count)
* to the described layout.
*/
static void
-print_dataset(zfs_handle_t *zhp, zfs_prop_t *fields, size_t count, int scripted)
+print_dataset(zfs_handle_t *zhp, zfs_proplist_t *pl, int scripted)
{
- int i;
+ boolean_t first = B_TRUE;
char property[ZFS_MAXPROPLEN];
+ nvlist_t *userprops = zfs_get_user_props(zhp);
+ nvlist_t *propval;
+ char *propstr;
+ boolean_t right_justify;
+ int width;
- for (i = 0; i < count; i++) {
- if (i != 0) {
+ for (; pl != NULL; pl = pl->pl_next) {
+ if (!first) {
if (scripted)
(void) printf("\t");
else
(void) printf(" ");
+ } else {
+ first = B_FALSE;
}
- if (zfs_prop_get(zhp, fields[i], property,
- sizeof (property), NULL, NULL, 0, B_FALSE) != 0)
- (void) strlcpy(property, "-", sizeof (property));
+ right_justify = B_FALSE;
+ if (pl->pl_prop != ZFS_PROP_INVAL) {
+ if (zfs_prop_get(zhp, pl->pl_prop, property,
+ sizeof (property), NULL, NULL, 0, B_FALSE) != 0)
+ propstr = "-";
+ else
+ propstr = property;
+
+ right_justify = zfs_prop_align_right(pl->pl_prop);
+ } else {
+ if (nvlist_lookup_nvlist(userprops,
+ pl->pl_user_prop, &propval) != 0)
+ propstr = "-";
+ else
+ verify(nvlist_lookup_string(propval,
+ ZFS_PROP_VALUE, &propstr) == 0);
+ }
+
+ width = pl->pl_width;
/*
* If this is being called in scripted mode, or if this is the
* last column and it is left-justified, don't include a width
* format specifier.
*/
- if (scripted || (i == count - 1 &&
- strchr(zfs_prop_column_format(fields[i]), '-') != NULL))
- (void) printf("%s", property);
- else /* LINTED - format specifier */
- (void) printf(zfs_prop_column_format(fields[i]),
- property);
+ if (scripted || (pl->pl_next == NULL && !right_justify))
+ (void) printf("%s", propstr);
+ else if (right_justify)
+ (void) printf("%*s", width, propstr);
+ else
+ (void) printf("%-*s", width, propstr);
}
(void) printf("\n");
@@ -1248,12 +1481,11 @@ list_callback(zfs_handle_t *zhp, void *data)
if (cbp->cb_first) {
if (!cbp->cb_scripted)
- print_header(cbp->cb_fields, cbp->cb_fieldcount);
+ print_header(cbp->cb_proplist);
cbp->cb_first = B_FALSE;
}
- print_dataset(zhp, cbp->cb_fields, cbp->cb_fieldcount,
- cbp->cb_scripted);
+ print_dataset(zhp, cbp->cb_proplist, cbp->cb_scripted);
return (0);
}
@@ -1273,14 +1505,10 @@ zfs_do_list(int argc, char **argv)
char *value;
int ret;
char *type_subopts[] = { "filesystem", "volume", "snapshot", NULL };
- char *badopt;
- int alloffset;
zfs_sort_column_t *sortcol = NULL;
/* check options */
while ((c = getopt(argc, argv, ":o:rt:Hs:S:")) != -1) {
- zfs_prop_t prop;
-
switch (c) {
case 'o':
fields = optarg;
@@ -1292,22 +1520,20 @@ zfs_do_list(int argc, char **argv)
scripted = B_TRUE;
break;
case 's':
- if ((prop = zfs_name_to_prop(optarg)) ==
- ZFS_PROP_INVAL) {
+ if (zfs_add_sort_column(&sortcol, optarg,
+ B_FALSE) != 0) {
(void) fprintf(stderr,
gettext("invalid property '%s'\n"), optarg);
usage(B_FALSE);
}
- zfs_add_sort_column(&sortcol, prop, B_FALSE);
break;
case 'S':
- if ((prop = zfs_name_to_prop(optarg)) ==
- ZFS_PROP_INVAL) {
+ if (zfs_add_sort_column(&sortcol, optarg,
+ B_TRUE) != 0) {
(void) fprintf(stderr,
gettext("invalid property '%s'\n"), optarg);
usage(B_FALSE);
}
- zfs_add_sort_column(&sortcol, prop, B_TRUE);
break;
case 't':
types = 0;
@@ -1354,31 +1580,16 @@ zfs_do_list(int argc, char **argv)
* normally include the name of the dataset. For 'zfs list', we always
* want this property to be first.
*/
- if (strcmp(fields, "all") == 0) {
- cb.cb_fields[0] = ZFS_PROP_NAME;
- alloffset = 1;
- } else {
- alloffset = 0;
- }
-
- if ((ret = zfs_get_proplist(fields, cb.cb_fields + alloffset,
- ZFS_NPROP_ALL - alloffset, &cb.cb_fieldcount, &badopt)) != 0) {
- if (ret == EINVAL)
- (void) fprintf(stderr, gettext("invalid property "
- "'%s'\n"), badopt);
- else
- (void) fprintf(stderr, gettext("too many properties "
- "specified\n"));
+ if (zfs_get_proplist(g_zfs, fields, &cb.cb_proplist) != 0)
usage(B_FALSE);
- }
- cb.cb_fieldcount += alloffset;
cb.cb_scripted = scripted;
cb.cb_first = B_TRUE;
- ret = zfs_for_each(argc, argv, recurse, types, sortcol,
+ ret = zfs_for_each(argc, argv, recurse, types, sortcol, &cb.cb_proplist,
list_callback, &cb);
+ zfs_free_proplist(cb.cb_proplist);
zfs_free_sort_columns(sortcol);
if (ret == 0 && cb.cb_first)
@@ -1652,7 +1863,6 @@ out:
typedef struct set_cbdata {
char *cb_propname;
char *cb_value;
- zfs_prop_t cb_prop;
} set_cbdata_t;
static int
@@ -1661,92 +1871,7 @@ set_callback(zfs_handle_t *zhp, void *data)
set_cbdata_t *cbp = data;
int ret = 1;
- /* don't allow setting of properties for snapshots */
- if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
- (void) fprintf(stderr, gettext("cannot set %s property for "
- "'%s': snapshot properties cannot be modified\n"),
- cbp->cb_propname, zfs_get_name(zhp));
- return (1);
- }
-
- /*
- * If we're changing the volsize, make sure the value is appropriate,
- * and set the reservation if this is a non-sparse volume.
- */
- if (cbp->cb_prop == ZFS_PROP_VOLSIZE &&
- zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
- uint64_t volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
- uint64_t avail = zfs_prop_get_int(zhp, ZFS_PROP_AVAILABLE);
- uint64_t reservation = zfs_prop_get_int(zhp,
- ZFS_PROP_RESERVATION);
- uint64_t blocksize = zfs_prop_get_int(zhp,
- ZFS_PROP_VOLBLOCKSIZE);
- uint64_t value;
-
- verify(zfs_nicestrtonum(cbp->cb_value, &value) == 0);
-
- if (value % blocksize != 0) {
- char buf[64];
-
- zfs_nicenum(blocksize, buf, sizeof (buf));
- (void) fprintf(stderr, gettext("cannot set %s for "
- "'%s': must be a multiple of volume block size "
- "(%s)\n"), cbp->cb_propname, zfs_get_name(zhp),
- buf);
- return (1);
- }
-
- if (value == 0) {
- (void) fprintf(stderr, gettext("cannot set %s for "
- "'%s': cannot be zero\n"), cbp->cb_propname,
- zfs_get_name(zhp));
- return (1);
- }
-
- if (volsize == reservation) {
- if (value > volsize && (value - volsize) > avail) {
- (void) fprintf(stderr, gettext("cannot set "
- "%s property for '%s': volume size exceeds "
- "amount of available space\n"),
- cbp->cb_propname, zfs_get_name(zhp));
- return (1);
- }
-
- if (zfs_prop_set(zhp, ZFS_PROP_RESERVATION,
- cbp->cb_value) != 0) {
- (void) fprintf(stderr, gettext("volsize and "
- "reservation must remain equal\n"));
- return (1);
- }
- }
- }
-
- /*
- * Do not allow the reservation to be set above the volume size. We do
- * this here instead of inside libzfs because libzfs violates this rule
- * internally.
- */
- if (cbp->cb_prop == ZFS_PROP_RESERVATION &&
- zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
- uint64_t value;
- uint64_t volsize;
-
- volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
- if (strcmp(cbp->cb_value, "none") == 0)
- value = 0;
- else
- verify(zfs_nicestrtonum(cbp->cb_value, &value) == 0);
-
- if (value > volsize) {
- (void) fprintf(stderr, gettext("cannot set %s "
- "for '%s': size is greater than current "
- "volume size\n"), cbp->cb_propname,
- zfs_get_name(zhp));
- return (-1);
- }
- }
-
- if (zfs_prop_set(zhp, cbp->cb_prop, cbp->cb_value) != 0) {
+ if (zfs_prop_set(zhp, cbp->cb_propname, cbp->cb_value) != 0) {
switch (libzfs_errno(g_zfs)) {
case EZFS_MOUNTFAILED:
(void) fprintf(stderr, gettext("property may be set "
@@ -1803,30 +1928,9 @@ zfs_do_set(int argc, char **argv)
gettext("missing property in property=value argument\n"));
usage(B_FALSE);
}
- if (*cb.cb_value == '\0') {
- (void) fprintf(stderr,
- gettext("missing value in property=value argument\n"));
- usage(B_FALSE);
- }
-
- /* get the property type */
- if ((cb.cb_prop = zfs_name_to_prop(cb.cb_propname)) ==
- ZFS_PROP_INVAL) {
- (void) fprintf(stderr,
- gettext("invalid property '%s'\n"), cb.cb_propname);
- usage(B_FALSE);
- }
-
- /*
- * Validate that the value is appropriate for this property. We do this
- * once now so we don't generate multiple errors each time we try to
- * apply it to a dataset.
- */
- if (zfs_prop_validate(g_zfs, cb.cb_prop, cb.cb_value, NULL) != 0)
- return (1);
return (zfs_for_each(argc - 2, argv + 2, B_FALSE,
- ZFS_TYPE_ANY, NULL, set_callback, &cb));
+ ZFS_TYPE_ANY, NULL, NULL, set_callback, &cb));
}
/*
@@ -2125,7 +2229,7 @@ share_mount_callback(zfs_handle_t *zhp, void *data)
share_mount_cbdata_t *cbp = data;
const char *cmdname = cbp->cb_type == OP_SHARE ? "share" : "mount";
struct mnttab mnt;
- uint64_t zoned;
+ uint64_t zoned, canmount;
if (cbp->cb_options == NULL)
mnt.mnt_mntopts = "";
@@ -2165,6 +2269,7 @@ share_mount_callback(zfs_handle_t *zhp, void *data)
sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0);
verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0);
+ canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
if (cbp->cb_type == OP_SHARE) {
if (strcmp(shareopts, "off") == 0) {
@@ -2205,6 +2310,15 @@ share_mount_callback(zfs_handle_t *zhp, void *data)
return (1);
}
+ if (!canmount) {
+ if (!cbp->cb_explicit)
+ return (0);
+
+ (void) fprintf(stderr, gettext("cannot %s '%s': 'canmount' "
+ "property is set to 'off'\n"), cmdname, zfs_get_name(zhp));
+ return (1);
+ }
+
/*
* At this point, we have verified that the mountpoint and/or shareopts
* are appropriate for auto management. Determine if the filesystem is
diff --git a/usr/src/cmd/zoneadm/Makefile b/usr/src/cmd/zoneadm/Makefile
index bf4e21d47e..cbe135d379 100644
--- a/usr/src/cmd/zoneadm/Makefile
+++ b/usr/src/cmd/zoneadm/Makefile
@@ -43,7 +43,7 @@ SRCS = $(OBJS:.o=.c)
POFILE=zoneadm_all.po
POFILES= $(OBJS:%.o=%.po)
-LDLIBS += -lzonecfg -lsocket -lgen -lpool -lbsm -lzfs -luuid
+LDLIBS += -lzonecfg -lsocket -lgen -lpool -lbsm -lzfs -luuid -lnvpair
.KEEP_STATE:
diff --git a/usr/src/cmd/zoneadm/zfs.c b/usr/src/cmd/zoneadm/zfs.c
index 1fe567b218..dfb17534a9 100644
--- a/usr/src/cmd/zoneadm/zfs.c
+++ b/usr/src/cmd/zoneadm/zfs.c
@@ -407,14 +407,27 @@ clone_snap(char *snapshot_name, char *zonepath)
int err;
zfs_handle_t *zhp;
zfs_handle_t *clone;
+ nvlist_t *props = NULL;
if ((zhp = zfs_open(g_zfs, snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL)
return (Z_NO_ENTRY);
(void) printf(gettext("Cloning snapshot %s\n"), snapshot_name);
- err = zfs_clone(zhp, zonepath);
+ if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 ||
+ nvlist_add_boolean_value(props,
+ zfs_prop_to_name(ZFS_PROP_SHARENFS), B_FALSE) != 0) {
+ nvlist_free(props);
+ (void) fprintf(stderr, gettext("could not create ZFS clone "
+ "%s: out of memory\n"), zonepath);
+ return (Z_ERR);
+ }
+
+ err = zfs_clone(zhp, zonepath, props);
zfs_close(zhp);
+
+ nvlist_free(props);
+
if (err != 0)
return (Z_ERR);
@@ -431,20 +444,11 @@ clone_snap(char *snapshot_name, char *zonepath)
"%s\n"), zfs_get_name(clone));
res = Z_ERR;
- } else {
- if (zfs_prop_set(clone, ZFS_PROP_SHARENFS, "off") != 0) {
- /* we won't consider this a failure */
- (void) fprintf(stderr, gettext("could not turn off the "
- "'sharenfs' property on ZFS clone %s\n"),
- zfs_get_name(clone));
- }
-
- if (clean_out_clone() != Z_OK) {
- (void) fprintf(stderr, gettext("could not remove the "
- "software inventory from ZFS clone %s\n"),
- zfs_get_name(clone));
- res = Z_ERR;
- }
+ } else if (clean_out_clone() != Z_OK) {
+ (void) fprintf(stderr, gettext("could not remove the "
+ "software inventory from ZFS clone %s\n"),
+ zfs_get_name(clone));
+ res = Z_ERR;
}
zfs_close(clone);
@@ -700,25 +704,33 @@ create_zfs_zonepath(char *zonepath)
{
zfs_handle_t *zhp;
char zfs_name[MAXPATHLEN];
+ nvlist_t *props = NULL;
if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK)
return;
- if (zfs_create(g_zfs, zfs_name, ZFS_TYPE_FILESYSTEM, NULL, NULL) != 0 ||
+ if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0 ||
+ nvlist_add_boolean_value(props, zfs_prop_to_name(ZFS_PROP_SHARENFS),
+ B_FALSE) != 0) {
+ nvlist_free(props);
+ (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
+ "out of memory\n"), zfs_name);
+ }
+
+ if (zfs_create(g_zfs, zfs_name, ZFS_TYPE_FILESYSTEM, props) != 0 ||
(zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_ANY)) == NULL) {
(void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
"%s\n"), zfs_name, libzfs_error_description(g_zfs));
+ nvlist_free(props);
return;
}
+ nvlist_free(props);
+
if (zfs_mount(zhp, NULL, 0) != 0) {
(void) fprintf(stderr, gettext("cannot mount ZFS dataset %s: "
"%s\n"), zfs_name, libzfs_error_description(g_zfs));
(void) zfs_destroy(zhp);
- } else if (zfs_prop_set(zhp, ZFS_PROP_SHARENFS, "off") != 0) {
- (void) fprintf(stderr, gettext("file system %s successfully "
- "created,\nbut could not turn off the 'sharenfs' "
- "property\n"), zfs_name);
} else {
if (chmod(zonepath, S_IRWXU) != 0) {
(void) fprintf(stderr, gettext("file system %s "
@@ -849,7 +861,8 @@ move_zfs(char *zonepath, char *new_zonepath)
if ((zhp = mount2zhandle(zonepath)) == NULL)
return (Z_ERR);
- if (zfs_prop_set(zhp, ZFS_PROP_MOUNTPOINT, new_zonepath) == 0) {
+ if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
+ new_zonepath) == 0) {
/*
* Clean up the old mount point. We ignore any failure since
* the zone is already successfully mounted on the new path.
diff --git a/usr/src/cmd/zoneadmd/vplat.c b/usr/src/cmd/zoneadmd/vplat.c
index 3bbaea3c15..88b79de7db 100644
--- a/usr/src/cmd/zoneadmd/vplat.c
+++ b/usr/src/cmd/zoneadmd/vplat.c
@@ -2605,7 +2605,8 @@ validate_datasets(zlog_t *zlogp)
* first because we'll get EPERM if it is already set.
*/
if (!zfs_prop_get_int(zhp, ZFS_PROP_ZONED) &&
- zfs_prop_set(zhp, ZFS_PROP_ZONED, "on") != 0) {
+ zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_ZONED),
+ "on") != 0) {
zerror(zlogp, B_FALSE, "cannot set 'zoned' "
"property for ZFS dataset '%s'\n",
dstab.zone_dataset_name);
diff --git a/usr/src/cmd/zpool/zpool_main.c b/usr/src/cmd/zpool/zpool_main.c
index 97e82dab46..bb175c9306 100644
--- a/usr/src/cmd/zpool/zpool_main.c
+++ b/usr/src/cmd/zpool/zpool_main.c
@@ -291,6 +291,14 @@ usage(boolean_t requested)
}
}
+ /*
+ * See comments at end of main().
+ */
+ if (getenv("ZFS_ABORT") != NULL) {
+ (void) printf("dumping core by request\n");
+ abort();
+ }
+
exit(requested ? 0 : 2);
}
@@ -572,7 +580,7 @@ zpool_do_create(int argc, char **argv)
if (altroot != NULL && altroot[0] != '/') {
(void) fprintf(stderr, gettext("invalid alternate root '%s': "
- "must be an absolute path\n"));
+ "must be an absolute path\n"), altroot);
nvlist_free(nvroot);
return (1);
}
@@ -651,7 +659,8 @@ zpool_do_create(int argc, char **argv)
if (pool != NULL) {
if (mountpoint != NULL)
verify(zfs_prop_set(pool,
- ZFS_PROP_MOUNTPOINT,
+ zfs_prop_to_name(
+ ZFS_PROP_MOUNTPOINT),
mountpoint) == 0);
if (zfs_mount(pool, NULL, 0) == 0)
ret = zfs_share(pool);
@@ -2362,6 +2371,7 @@ zpool_do_scrub(int argc, char **argv)
typedef struct status_cbdata {
int cb_count;
+ boolean_t cb_allpools;
boolean_t cb_verbose;
boolean_t cb_explain;
boolean_t cb_first;
@@ -2685,8 +2695,15 @@ status_callback(zpool_handle_t *zhp, void *data)
* If we were given 'zpool status -x', only report those pools with
* problems.
*/
- if (reason == ZPOOL_STATUS_OK && cbp->cb_explain)
+ if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
+ if (!cbp->cb_allpools) {
+ (void) printf(gettext("pool '%s' is healthy\n"),
+ zpool_get_name(zhp));
+ if (cbp->cb_first)
+ cbp->cb_first = B_FALSE;
+ }
return (0);
+ }
if (cbp->cb_first)
cbp->cb_first = B_FALSE;
@@ -2852,8 +2869,8 @@ status_callback(zpool_handle_t *zhp, void *data)
(void) printf(gettext("errors: No known data "
"errors\n"));
else if (!cbp->cb_verbose)
- (void) printf(gettext("errors: %d data errors, "
- "use '-v' for a list\n"), nerr);
+ (void) printf(gettext("errors: %llu data "
+ "errors, use '-v' for a list\n"), nerr);
else
print_error_log(zhp);
}
@@ -2901,20 +2918,15 @@ zpool_do_status(int argc, char **argv)
cb.cb_first = B_TRUE;
+ if (argc == 0)
+ cb.cb_allpools = B_TRUE;
+
ret = for_each_pool(argc, argv, B_TRUE, status_callback, &cb);
if (argc == 0 && cb.cb_count == 0)
(void) printf(gettext("no pools available\n"));
- else if (cb.cb_explain && cb.cb_first) {
- if (argc == 0) {
- (void) printf(gettext("all pools are healthy\n"));
- } else {
- int i;
- for (i = 0; i < argc; i++)
- (void) printf(gettext("pool '%s' is healthy\n"),
- argv[i]);
- }
- }
+ else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
+ (void) printf(gettext("all pools are healthy\n"));
return (ret);
}
diff --git a/usr/src/common/zfs/zfs_prop.c b/usr/src/common/zfs/zfs_prop.c
index fe9e11019f..8b2e7c3f93 100644
--- a/usr/src/common/zfs/zfs_prop.c
+++ b/usr/src/common/zfs/zfs_prop.c
@@ -77,86 +77,89 @@ typedef struct {
int pd_types;
const char *pd_values;
const char *pd_colname;
- const char *pd_colfmt;
+ boolean_t pd_rightalign;
} prop_desc_t;
static prop_desc_t zfs_prop_table[ZFS_NPROP_ALL] = {
{ "type", prop_type_string, 0, NULL, prop_readonly,
- ZFS_TYPE_ANY, "filesystem | volume | snapshot", "TYPE", "%10s" },
+ ZFS_TYPE_ANY, "filesystem | volume | snapshot", "TYPE", B_TRUE },
{ "creation", prop_type_number, 0, NULL, prop_readonly,
- ZFS_TYPE_ANY, "<date>", "CREATION", "%-20s" },
+ ZFS_TYPE_ANY, "<date>", "CREATION", B_FALSE },
{ "used", prop_type_number, 0, NULL, prop_readonly,
- ZFS_TYPE_ANY, "<size>", "USED", "%5s" },
+ ZFS_TYPE_ANY, "<size>", "USED", B_TRUE },
{ "available", prop_type_number, 0, NULL, prop_readonly,
- ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>", "AVAIL", "%5s" },
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>", "AVAIL", B_TRUE },
{ "referenced", prop_type_number, 0, NULL, prop_readonly,
ZFS_TYPE_ANY,
- "<size>", "REFER", "%5s" },
+ "<size>", "REFER", B_TRUE },
{ "compressratio", prop_type_number, 0, NULL, prop_readonly,
- ZFS_TYPE_ANY, "<1.00x or higher if compressed>", "RATIO", "%5s" },
+ ZFS_TYPE_ANY, "<1.00x or higher if compressed>", "RATIO", B_TRUE },
{ "mounted", prop_type_boolean, 0, NULL, prop_readonly,
- ZFS_TYPE_FILESYSTEM, "yes | no | -", "MOUNTED", "%7s" },
+ ZFS_TYPE_FILESYSTEM, "yes | no | -", "MOUNTED", B_TRUE },
{ "origin", prop_type_string, 0, NULL, prop_readonly,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<snapshot>", "ORIGIN",
- "%-20s" },
+ B_FALSE },
{ "quota", prop_type_number, 0, NULL, prop_default,
- ZFS_TYPE_FILESYSTEM, "<size> | none", "QUOTA", "%5s" },
+ ZFS_TYPE_FILESYSTEM, "<size> | none", "QUOTA", B_TRUE },
{ "reservation", prop_type_number, 0, NULL, prop_default,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "<size> | none", "RESERV", "%6s" },
+ "<size> | none", "RESERV", B_TRUE },
{ "volsize", prop_type_number, 0, NULL, prop_default,
- ZFS_TYPE_VOLUME, "<size>", "VOLSIZE", "%7s" },
+ ZFS_TYPE_VOLUME, "<size>", "VOLSIZE", B_TRUE },
{ "volblocksize", prop_type_number, 8192, NULL, prop_readonly,
- ZFS_TYPE_VOLUME, "512 to 128k, power of 2", "VOLBLOCK", "%8s" },
+ ZFS_TYPE_VOLUME, "512 to 128k, power of 2", "VOLBLOCK", B_TRUE },
{ "recordsize", prop_type_number, SPA_MAXBLOCKSIZE, NULL,
prop_inherit,
ZFS_TYPE_FILESYSTEM,
- "512 to 128k, power of 2", "RECSIZE", "%7s" },
+ "512 to 128k, power of 2", "RECSIZE", B_TRUE },
{ "mountpoint", prop_type_string, 0, "/", prop_inherit,
ZFS_TYPE_FILESYSTEM,
- "<path> | legacy | none", "MOUNTPOINT", "%-20s" },
+ "<path> | legacy | none", "MOUNTPOINT", B_FALSE },
{ "sharenfs", prop_type_string, 0, "off", prop_inherit,
ZFS_TYPE_FILESYSTEM,
- "on | off | share(1M) options", "SHARENFS", "%-15s" },
+ "on | off | share(1M) options", "SHARENFS", B_FALSE },
{ "checksum", prop_type_index, ZIO_CHECKSUM_DEFAULT, "on",
prop_inherit, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "on | off | fletcher2 | fletcher4 | sha256", "CHECKSUM", "%10s" },
+ "on | off | fletcher2 | fletcher4 | sha256", "CHECKSUM", B_TRUE },
{ "compression", prop_type_index, ZIO_COMPRESS_DEFAULT, "off",
prop_inherit, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "on | off | lzjb", "COMPRESS", "%8s" },
+ "on | off | lzjb", "COMPRESS", B_TRUE },
{ "atime", prop_type_boolean, 1, NULL, prop_inherit,
ZFS_TYPE_FILESYSTEM,
- "on | off", "ATIME", "%5s" },
+ "on | off", "ATIME", B_TRUE },
{ "devices", prop_type_boolean, 1, NULL, prop_inherit,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
- "on | off", "DEVICES", "%7s" },
+ "on | off", "DEVICES", B_TRUE },
{ "exec", prop_type_boolean, 1, NULL, prop_inherit,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
- "on | off", "EXEC", "%4s" },
+ "on | off", "EXEC", B_TRUE },
{ "setuid", prop_type_boolean, 1, NULL, prop_inherit,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "SETUID",
- "%6s" },
+ B_TRUE },
{ "readonly", prop_type_boolean, 0, NULL, prop_inherit,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "on | off", "RDONLY", "%6s" },
+ "on | off", "RDONLY", B_TRUE },
{ "zoned", prop_type_boolean, 0, NULL, prop_inherit,
ZFS_TYPE_FILESYSTEM,
- "on | off", "ZONED", "%5s" },
+ "on | off", "ZONED", B_TRUE },
{ "snapdir", prop_type_index, ZFS_SNAPDIR_HIDDEN, "hidden",
prop_inherit,
ZFS_TYPE_FILESYSTEM,
- "hidden | visible", "SNAPDIR", "%7s" },
- { "aclmode", prop_type_index, GROUPMASK, "groupmask", prop_inherit,
+ "hidden | visible", "SNAPDIR", B_TRUE },
+ { "aclmode", prop_type_index, ZFS_ACL_GROUPMASK, "groupmask",
+ prop_inherit, ZFS_TYPE_FILESYSTEM,
+ "discard | groupmask | passthrough", "ACLMODE", B_TRUE },
+ { "aclinherit", prop_type_index, ZFS_ACL_SECURE, "secure",
+ prop_inherit, ZFS_TYPE_FILESYSTEM,
+ "discard | noallow | secure | passthrough", "ACLINHERIT", B_TRUE },
+ { "canmount", prop_type_boolean, 1, NULL, prop_default,
ZFS_TYPE_FILESYSTEM,
- "discard | groupmask | passthrough", "ACLMODE", "%11s" },
- { "aclinherit", prop_type_index, SECURE, "secure", prop_inherit,
- ZFS_TYPE_FILESYSTEM,
- "discard | noallow | secure | passthrough", "ACLINHERIT", "%11s" },
+ "on | off", "CANMOUNT", B_TRUE },
{ "createtxg", prop_type_number, 0, NULL, prop_readonly,
ZFS_TYPE_ANY, NULL, NULL, NULL},
{ "name", prop_type_string, 0, NULL, prop_readonly,
ZFS_TYPE_ANY,
- NULL, "NAME", "%-20s" },
+ NULL, "NAME", B_FALSE },
};
zfs_proptype_t
@@ -165,8 +168,8 @@ zfs_prop_get_type(zfs_prop_t prop)
return (zfs_prop_table[prop].pd_proptype);
}
-static int
-propname_match(const char *p, int prop, size_t len)
+static boolean_t
+propname_match(const char *p, zfs_prop_t prop, size_t len)
{
const char *propname = zfs_prop_table[prop].pd_name;
#ifndef _KERNEL
@@ -176,16 +179,16 @@ propname_match(const char *p, int prop, size_t len)
#ifndef _KERNEL
if (colname == NULL)
- return (0);
+ return (B_FALSE);
#endif
if (len == strlen(propname) &&
strncmp(p, propname, len) == 0)
- return (1);
+ return (B_TRUE);
#ifndef _KERNEL
if (len != strlen(colname))
- return (0);
+ return (B_FALSE);
for (c = 0; c < len; c++)
if (p[c] != tolower(colname[c]))
@@ -193,7 +196,7 @@ propname_match(const char *p, int prop, size_t len)
return (colname[c] == '\0');
#else
- return (0);
+ return (B_FALSE);
#endif
}
@@ -215,6 +218,42 @@ zfs_name_to_prop(const char *propname)
}
/*
+ * For user property names, we allow all lowercase alphanumeric characters, plus
+ * a few useful punctuation characters.
+ */
+static int
+valid_char(char c)
+{
+ return ((c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') ||
+ c == '-' || c == '_' || c == '.' || c == ':');
+}
+
+/*
+ * Returns true if this is a valid user-defined property (one with a ':').
+ */
+boolean_t
+zfs_prop_user(const char *name)
+{
+ int i;
+ char c;
+ boolean_t foundsep = B_FALSE;
+
+ for (i = 0; i < strlen(name); i++) {
+ c = name[i];
+ if (!valid_char(c))
+ return (B_FALSE);
+ if (c == ':')
+ foundsep = B_TRUE;
+ }
+
+ if (!foundsep)
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+/*
* Return the default value for the given property.
*/
const char *
@@ -238,7 +277,6 @@ zfs_prop_readonly(zfs_prop_t prop)
return (zfs_prop_table[prop].pd_attr == prop_readonly);
}
-#ifndef _KERNEL
/*
* Given a property ID, returns the corresponding name.
*/
@@ -257,6 +295,117 @@ zfs_prop_inheritable(zfs_prop_t prop)
return (zfs_prop_table[prop].pd_attr == prop_inherit);
}
+#ifndef _KERNEL
+
+typedef struct zfs_index {
+ const char *name;
+ uint64_t index;
+} zfs_index_t;
+
+static zfs_index_t checksum_table[] = {
+ { "on", ZIO_CHECKSUM_ON },
+ { "off", ZIO_CHECKSUM_OFF },
+ { "fletcher2", ZIO_CHECKSUM_FLETCHER_2 },
+ { "fletcher4", ZIO_CHECKSUM_FLETCHER_4 },
+ { "sha256", ZIO_CHECKSUM_SHA256 },
+ { NULL }
+};
+
+static zfs_index_t compress_table[] = {
+ { "on", ZIO_COMPRESS_ON },
+ { "off", ZIO_COMPRESS_OFF },
+ { "lzjb", ZIO_COMPRESS_LZJB },
+ { NULL }
+};
+
+static zfs_index_t snapdir_table[] = {
+ { "hidden", ZFS_SNAPDIR_HIDDEN },
+ { "visible", ZFS_SNAPDIR_VISIBLE },
+ { NULL }
+};
+
+static zfs_index_t acl_mode_table[] = {
+ { "discard", ZFS_ACL_DISCARD },
+ { "groupmask", ZFS_ACL_GROUPMASK },
+ { "passthrough", ZFS_ACL_PASSTHROUGH },
+ { NULL }
+};
+
+static zfs_index_t acl_inherit_table[] = {
+ { "discard", ZFS_ACL_DISCARD },
+ { "noallow", ZFS_ACL_NOALLOW },
+ { "secure", ZFS_ACL_SECURE },
+ { "passthrough", ZFS_ACL_PASSTHROUGH },
+ { NULL }
+};
+
+static zfs_index_t *
+zfs_prop_index_table(zfs_prop_t prop)
+{
+ switch (prop) {
+ case ZFS_PROP_CHECKSUM:
+ return (checksum_table);
+ break;
+ case ZFS_PROP_COMPRESSION:
+ return (compress_table);
+ break;
+ case ZFS_PROP_SNAPDIR:
+ return (snapdir_table);
+ break;
+ case ZFS_PROP_ACLMODE:
+ return (acl_mode_table);
+ break;
+ case ZFS_PROP_ACLINHERIT:
+ return (acl_inherit_table);
+ break;
+ default:
+ return (NULL);
+ }
+}
+
+
+/*
+ * Tables of index types, plus functions to convert between the user view
+ * (strings) and internal representation (uint64_t).
+ */
+int
+zfs_prop_string_to_index(zfs_prop_t prop, const char *string, uint64_t *index)
+{
+ zfs_index_t *table;
+ int i;
+
+ if ((table = zfs_prop_index_table(prop)) == NULL)
+ return (-1);
+
+ for (i = 0; table[i].name != NULL; i++) {
+ if (strcmp(string, table[i].name) == 0) {
+ *index = table[i].index;
+ return (0);
+ }
+ }
+
+ return (-1);
+}
+
+int
+zfs_prop_index_to_string(zfs_prop_t prop, uint64_t index, const char **string)
+{
+ zfs_index_t *table;
+ int i;
+
+ if ((table = zfs_prop_index_table(prop)) == NULL)
+ return (-1);
+
+ for (i = 0; table[i].name != NULL; i++) {
+ if (table[i].index == index) {
+ *string = table[i].name;
+ return (0);
+ }
+ }
+
+ return (-1);
+}
+
/*
* Returns TRUE if the property applies to the given dataset types.
*/
@@ -299,110 +448,75 @@ zfs_prop_column_name(zfs_prop_t prop)
}
/*
- * Returns the column formatting for the given property. Used only in
- * 'zfs list -o', but centralized here with the other property information.
+ * Returns whether the given property should be displayed right-justified for
+ * 'zfs list'.
*/
-const char *
-zfs_prop_column_format(zfs_prop_t prop)
+boolean_t
+zfs_prop_align_right(zfs_prop_t prop)
{
- return (zfs_prop_table[prop].pd_colfmt);
+ return (zfs_prop_table[prop].pd_rightalign);
}
/*
- * Given a comma-separated list of fields, fills in the specified array with a
- * list of properties. The keyword "all" can be used to specify all properties.
- * The 'count' parameter returns the number of matching properties placed into
- * the list. The 'props' parameter must point to an array of at least
- * ZFS_NPROP_ALL elements.
+ * Determines the minimum width for the column, and indicates whether it's fixed
+ * or not. Only string columns are non-fixed.
*/
-int
-zfs_get_proplist(char *fields, zfs_prop_t *props, int max,
- int *count, char **badopt)
+size_t
+zfs_prop_width(zfs_prop_t prop, boolean_t *fixed)
{
+ prop_desc_t *pd = &zfs_prop_table[prop];
+ zfs_index_t *idx;
+ size_t ret;
int i;
- size_t len;
- char *s, *p;
- *count = 0;
+ *fixed = B_TRUE;
/*
- * Check for the special value "all", which indicates all properties
- * should be displayed.
+ * Start with the width of the column name.
*/
- if (strcmp(fields, "all") == 0) {
- if (max < ZFS_NPROP_VISIBLE)
- return (EOVERFLOW);
-
- for (i = 0; i < ZFS_NPROP_VISIBLE; i++)
- props[i] = i;
- *count = ZFS_NPROP_VISIBLE;
- return (0);
- }
+ ret = strlen(pd->pd_colname);
/*
- * It would be nice to use getsubopt() here, but the inclusion of column
- * aliases makes this more effort than it's worth.
+ * For fixed-width values, make sure the width is large enough to hold
+ * any possible value.
*/
- s = fields;
- while (*s != '\0') {
- if ((p = strchr(s, ',')) == NULL) {
- len = strlen(s);
- p = s + len;
- } else {
- len = p - s;
- }
-
+ switch (pd->pd_proptype) {
+ case prop_type_number:
/*
- * Check for empty options.
+ * The maximum length of a human-readable number is 5 characters
+ * ("20.4M", for example).
*/
- if (len == 0) {
- *badopt = "";
- return (EINVAL);
- }
-
+ if (ret < 5)
+ ret = 5;
/*
- * Check all regular property names.
+ * 'creation' is handled specially because it's a number
+ * internally, but displayed as a date string.
*/
- for (i = 0; i < ZFS_NPROP_ALL; i++) {
- if (propname_match(s, i, len))
- break;
- }
-
+ if (prop == ZFS_PROP_CREATION)
+ *fixed = B_FALSE;
+ break;
+ case prop_type_boolean:
/*
- * If no column is specified, then return failure, setting
- * 'badopt' to point to the invalid option.
+ * The maximum length of a boolean value is 3 characters, for
+ * "off".
*/
- if (i == ZFS_NPROP_ALL) {
- s[len] = '\0';
- *badopt = s;
- return (EINVAL);
+ if (ret < 3)
+ ret = 3;
+ break;
+ case prop_type_index:
+ idx = zfs_prop_index_table(prop);
+ for (i = 0; idx[i].name != NULL; i++) {
+ if (strlen(idx[i].name) > ret)
+ ret = strlen(idx[i].name);
}
+ break;
- /*
- * If the user specified too many options (by using the same one
- * multiple times). return an error with 'badopt' set to NULL to
- * indicate this condition.
- */
- if (*count == max)
- return (EOVERFLOW);
-
- props[*count] = i;
- *count += 1;
-
- s = p;
- if (*s == ',')
- s++;
- }
-
- /*
- * If no fields were specified, return an error.
- */
- if (*count == 0) {
- *badopt = "";
- return (EINVAL);
+ case prop_type_string:
+ *fixed = B_FALSE;
+ break;
}
- return (0);
+ return (ret);
}
#endif
diff --git a/usr/src/common/zfs/zfs_prop.h b/usr/src/common/zfs/zfs_prop.h
index f95574acc9..2a89f0551f 100644
--- a/usr/src/common/zfs/zfs_prop.h
+++ b/usr/src/common/zfs/zfs_prop.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -48,6 +47,9 @@ typedef enum {
} zfs_proptype_t;
zfs_proptype_t zfs_prop_get_type(zfs_prop_t);
+int zfs_prop_string_to_index(zfs_prop_t, const char *, uint64_t *);
+int zfs_prop_index_to_string(zfs_prop_t, uint64_t, const char **);
+size_t zfs_prop_width(zfs_prop_t, boolean_t *);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
index 601bdb2f18..4459c70710 100644
--- a/usr/src/lib/libzfs/common/libzfs.h
+++ b/usr/src/lib/libzfs/common/libzfs.h
@@ -201,10 +201,6 @@ extern nvlist_t *zpool_get_config(zpool_handle_t *, nvlist_t **);
extern int zpool_refresh_stats(zpool_handle_t *, boolean_t *);
extern int zpool_get_errlog(zpool_handle_t *, nvlist_t ***, size_t *);
-#define ZPOOL_ERR_DATASET "dataset"
-#define ZPOOL_ERR_OBJECT "object"
-#define ZPOOL_ERR_RANGE "range"
-
/*
* Import and export functions
*/
@@ -246,25 +242,36 @@ typedef enum {
* Property management functions. Some functions are shared with the kernel,
* and are found in sys/fs/zfs.h.
*/
-const char *zfs_prop_to_name(zfs_prop_t);
-int zfs_prop_set(zfs_handle_t *, zfs_prop_t, const char *);
-int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t, zfs_source_t *,
- char *, size_t, boolean_t);
-int zfs_prop_get_numeric(zfs_handle_t *, zfs_prop_t, uint64_t *, zfs_source_t *,
- char *, size_t);
-uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
-int zfs_prop_validate(libzfs_handle_t *, zfs_prop_t, const char *, uint64_t *);
-int zfs_prop_inheritable(zfs_prop_t);
-int zfs_prop_inherit(zfs_handle_t *, zfs_prop_t);
-const char *zfs_prop_values(zfs_prop_t);
-int zfs_prop_valid_for_type(zfs_prop_t, int);
-const char *zfs_prop_default_string(zfs_prop_t prop);
-uint64_t zfs_prop_default_numeric(zfs_prop_t);
-int zfs_prop_is_string(zfs_prop_t prop);
-const char *zfs_prop_column_name(zfs_prop_t);
-const char *zfs_prop_column_format(zfs_prop_t);
-int zfs_get_proplist(char *fields, zfs_prop_t *proplist, int max, int *count,
- char **badopt);
+extern const char *zfs_prop_to_name(zfs_prop_t);
+extern int zfs_prop_set(zfs_handle_t *, const char *, const char *);
+extern int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t,
+ zfs_source_t *, char *, size_t, boolean_t);
+extern int zfs_prop_get_numeric(zfs_handle_t *, zfs_prop_t, uint64_t *,
+ zfs_source_t *, char *, size_t);
+extern uint64_t zfs_prop_get_int(zfs_handle_t *, zfs_prop_t);
+extern const char *zfs_prop_get_string(zfs_handle_t *, zfs_prop_t);
+extern int zfs_prop_inherit(zfs_handle_t *, const char *);
+extern const char *zfs_prop_values(zfs_prop_t);
+extern int zfs_prop_valid_for_type(zfs_prop_t, int);
+extern const char *zfs_prop_default_string(zfs_prop_t prop);
+extern uint64_t zfs_prop_default_numeric(zfs_prop_t);
+extern int zfs_prop_is_string(zfs_prop_t prop);
+extern const char *zfs_prop_column_name(zfs_prop_t);
+extern boolean_t zfs_prop_align_right(zfs_prop_t);
+
+typedef struct zfs_proplist {
+ zfs_prop_t pl_prop;
+ char *pl_user_prop;
+ struct zfs_proplist *pl_next;
+ boolean_t pl_all;
+ size_t pl_width;
+ boolean_t pl_fixed;
+} zfs_proplist_t;
+
+extern int zfs_get_proplist(libzfs_handle_t *, char *, zfs_proplist_t **);
+extern void zfs_free_proplist(zfs_proplist_t *);
+extern int zfs_expand_proplist(zfs_handle_t *, zfs_proplist_t **);
+extern nvlist_t *zfs_get_user_props(zfs_handle_t *);
#define ZFS_MOUNTPOINT_NONE "none"
#define ZFS_MOUNTPOINT_LEGACY "legacy"
@@ -283,10 +290,10 @@ extern int zfs_iter_snapshots(zfs_handle_t *, zfs_iter_f, void *);
* Functions to create and destroy datasets.
*/
extern int zfs_create(libzfs_handle_t *, const char *, zfs_type_t,
- const char *, const char *);
+ nvlist_t *);
extern int zfs_destroy(zfs_handle_t *);
extern int zfs_destroy_snaps(zfs_handle_t *, char *);
-extern int zfs_clone(zfs_handle_t *, const char *);
+extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *);
extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t);
extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, int);
extern int zfs_rename(zfs_handle_t *, const char *);
@@ -331,7 +338,7 @@ extern int zfs_unshareall(zfs_handle_t *);
* Utility function to convert a number to a human-readable form.
*/
extern void zfs_nicenum(uint64_t, char *, size_t);
-extern int zfs_nicestrtonum(const char *, uint64_t *);
+extern int zfs_nicestrtonum(libzfs_handle_t *, const char *, uint64_t *);
/*
* Pool destroy special. Remove the device information without destroying
diff --git a/usr/src/lib/libzfs/common/libzfs_changelist.c b/usr/src/lib/libzfs/common/libzfs_changelist.c
index 7b7b5cd9d4..6bc42d16e5 100644
--- a/usr/src/lib/libzfs/common/libzfs_changelist.c
+++ b/usr/src/lib/libzfs/common/libzfs_changelist.c
@@ -107,7 +107,7 @@ changelist_prefix(prop_changelist_t *clp)
* If we have a volume and this was a rename, remove the
* /dev/zvol links
*/
- if (cn->cn_handle->zfs_volblocksize &&
+ if (ZFS_IS_VOLUME(cn->cn_handle) &&
clp->cl_realprop == ZFS_PROP_NAME) {
if (zvol_remove_link(cn->cn_handle->zfs_hdl,
cn->cn_handle->zfs_name) != 0)
@@ -166,7 +166,7 @@ changelist_postfix(prop_changelist_t *clp)
* If this is a volume and we're doing a rename, recreate the
* /dev/zvol links.
*/
- if (cn->cn_handle->zfs_volblocksize &&
+ if (ZFS_IS_VOLUME(cn->cn_handle) &&
clp->cl_realprop == ZFS_PROP_NAME) {
if (zvol_create_link(cn->cn_handle->zfs_hdl,
cn->cn_handle->zfs_name) != 0)
@@ -358,7 +358,7 @@ change_one(zfs_handle_t *zhp, void *data)
* rename, then always add it to the changelist.
*/
- if (!(zhp->zfs_volblocksize && clp->cl_realprop == ZFS_PROP_NAME) &&
+ if (!(ZFS_IS_VOLUME(zhp) && clp->cl_realprop == ZFS_PROP_NAME) &&
zfs_prop_get(zhp, clp->cl_prop, property,
sizeof (property), &sourcetype, where, sizeof (where),
B_FALSE) != 0) {
@@ -508,6 +508,8 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags)
} else if (prop == ZFS_PROP_ZONED) {
clp->cl_prop = ZFS_PROP_MOUNTPOINT;
clp->cl_allchildren = B_TRUE;
+ } else if (prop == ZFS_PROP_CANMOUNT) {
+ clp->cl_prop = ZFS_PROP_MOUNTPOINT;
} else {
clp->cl_prop = prop;
}
diff --git a/usr/src/lib/libzfs/common/libzfs_config.c b/usr/src/lib/libzfs/common/libzfs_config.c
index 593131cea6..d8fbd2ecb5 100644
--- a/usr/src/lib/libzfs/common/libzfs_config.c
+++ b/usr/src/lib/libzfs/common/libzfs_config.c
@@ -129,19 +129,9 @@ namespace_reload(libzfs_handle_t *hdl)
return (no_memory(hdl));
}
- /*
- * Issue the ZFS_IOC_POOL_CONFIGS ioctl.
- * This can fail for one of two reasons:
- *
- * EEXIST The generation counts match, nothing to do.
- * ENOMEM The zc_config_dst buffer isn't large enough to
- * hold the config; zc_config_dst_size will have
- * been modified to tell us how much to allocate.
- */
- zc.zc_config_dst_size = 1024;
- if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
- zfs_alloc(hdl, zc.zc_config_dst_size)) == NULL)
+ if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
return (-1);
+
for (;;) {
zc.zc_cookie = hdl->libzfs_ns_gen;
if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
@@ -150,18 +140,18 @@ namespace_reload(libzfs_handle_t *hdl)
/*
* The namespace hasn't changed.
*/
- free((void *)(uintptr_t)zc.zc_config_dst);
+ zcmd_free_nvlists(&zc);
return (0);
case ENOMEM:
- free((void *)(uintptr_t)zc.zc_config_dst);
- if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
- zfs_alloc(hdl, zc.zc_config_dst_size))
- == NULL)
+ if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+ zcmd_free_nvlists(&zc);
return (-1);
+ }
break;
default:
+ zcmd_free_nvlists(&zc);
return (zfs_standard_error(hdl, errno,
dgettext(TEXT_DOMAIN, "failed to read "
"pool configuration")));
@@ -172,13 +162,12 @@ namespace_reload(libzfs_handle_t *hdl)
}
}
- if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst,
- zc.zc_config_dst_size, &config, 0) != 0) {
- free((void *)(uintptr_t)zc.zc_config_dst);
- return (no_memory(hdl));
+ if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
}
- free((void *)(uintptr_t)zc.zc_config_dst);
+ zcmd_free_nvlists(&zc);
/*
* Clear out any existing configuration information.
@@ -256,6 +245,7 @@ zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
zfs_cmd_t zc = { 0 };
int error;
nvlist_t *config;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
*missing = B_FALSE;
(void) strcpy(zc.zc_name, zhp->zpool_name);
@@ -263,9 +253,7 @@ zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
if (zhp->zpool_config_size == 0)
zhp->zpool_config_size = 1 << 16;
- zc.zc_config_dst_size = zhp->zpool_config_size;
- if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
- zfs_alloc(zhp->zpool_hdl, zc.zc_config_dst_size)) == NULL)
+ if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0)
return (-1);
for (;;) {
@@ -279,13 +267,12 @@ zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
}
if (errno == ENOMEM) {
- free((void *)(uintptr_t)zc.zc_config_dst);
- if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
- zfs_alloc(zhp->zpool_hdl,
- zc.zc_config_dst_size)) == NULL)
+ if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+ zcmd_free_nvlists(&zc);
return (-1);
+ }
} else {
- free((void *)(uintptr_t)zc.zc_config_dst);
+ zcmd_free_nvlists(&zc);
if (errno == ENOENT || errno == EINVAL)
*missing = B_TRUE;
zhp->zpool_state = POOL_STATE_UNAVAIL;
@@ -293,14 +280,14 @@ zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
}
}
- if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst,
- zc.zc_config_dst_size, &config, 0) != 0) {
- free((void *)(uintptr_t)zc.zc_config_dst);
- return (no_memory(zhp->zpool_hdl));
+ if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
+ zcmd_free_nvlists(&zc);
+ return (-1);
}
- zhp->zpool_config_size = zc.zc_config_dst_size;
- free((void *)(uintptr_t)zc.zc_config_dst);
+ zcmd_free_nvlists(&zc);
+
+ zhp->zpool_config_size = zc.zc_nvlist_dst_size;
if (set_pool_health(config) != 0) {
nvlist_free(config);
diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c
index c8908e2ce3..ffef8ad8ed 100644
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c
@@ -43,6 +43,7 @@
#include <sys/spa.h>
#include <sys/zio.h>
+#include <sys/zap.h>
#include <libzfs.h>
#include "zfs_namecheck.h"
@@ -186,27 +187,57 @@ zfs_name_valid(const char *name, zfs_type_t type)
}
/*
+ * This function takes the raw DSL properties, and filters out the user-defined
+ * properties into a separate nvlist.
+ */
+static int
+process_user_props(zfs_handle_t *zhp)
+{
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ nvpair_t *elem;
+ nvlist_t *propval;
+
+ nvlist_free(zhp->zfs_user_props);
+
+ if (nvlist_alloc(&zhp->zfs_user_props, NV_UNIQUE_NAME, 0) != 0)
+ return (no_memory(hdl));
+
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) {
+ if (!zfs_prop_user(nvpair_name(elem)))
+ continue;
+
+ verify(nvpair_value_nvlist(elem, &propval) == 0);
+ if (nvlist_add_nvlist(zhp->zfs_user_props,
+ nvpair_name(elem), propval) != 0)
+ return (no_memory(hdl));
+ }
+
+ return (0);
+}
+
+/*
* Utility function to gather stats (objset and zpl) for the given object.
*/
static int
get_stats(zfs_handle_t *zhp)
{
zfs_cmd_t zc = { 0 };
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- if ((zc.zc_config_src = (uint64_t)(uintptr_t)malloc(1024)) == NULL)
+ if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
return (-1);
- zc.zc_config_src_size = 1024;
while (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) {
if (errno == ENOMEM) {
- free((void *)(uintptr_t)zc.zc_config_src);
- if ((zc.zc_config_src = (uint64_t)(uintptr_t)
- malloc(zc.zc_config_src_size)) == NULL)
+ if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+ zcmd_free_nvlists(&zc);
return (-1);
+ }
} else {
- free((void *)(uintptr_t)zc.zc_config_src);
+ zcmd_free_nvlists(&zc);
return (-1);
}
}
@@ -214,23 +245,24 @@ get_stats(zfs_handle_t *zhp)
bcopy(&zc.zc_objset_stats, &zhp->zfs_dmustats,
sizeof (zc.zc_objset_stats));
- (void) strcpy(zhp->zfs_root, zc.zc_root);
+ (void) strlcpy(zhp->zfs_root, zc.zc_value, sizeof (zhp->zfs_root));
if (zhp->zfs_props) {
nvlist_free(zhp->zfs_props);
zhp->zfs_props = NULL;
}
- if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_src,
- zc.zc_config_src_size, &zhp->zfs_props, 0) != 0) {
- free((void *)(uintptr_t)zc.zc_config_src);
+ if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zfs_props) != 0) {
+ zcmd_free_nvlists(&zc);
return (-1);
}
- zhp->zfs_volsize = zc.zc_volsize;
- zhp->zfs_volblocksize = zc.zc_volblocksize;
+ zcmd_free_nvlists(&zc);
- free((void *)(uintptr_t)zc.zc_config_src);
+ zhp->zfs_volstats = zc.zc_vol_stats;
+
+ if (process_user_props(zhp) != 0)
+ return (-1);
return (0);
}
@@ -373,64 +405,11 @@ zfs_close(zfs_handle_t *zhp)
{
if (zhp->zfs_mntopts)
free(zhp->zfs_mntopts);
- if (zhp->zfs_props)
- nvlist_free(zhp->zfs_props);
+ nvlist_free(zhp->zfs_props);
+ nvlist_free(zhp->zfs_user_props);
free(zhp);
}
-struct {
- const char *name;
- uint64_t value;
-} checksum_table[] = {
- { "on", ZIO_CHECKSUM_ON },
- { "off", ZIO_CHECKSUM_OFF },
- { "fletcher2", ZIO_CHECKSUM_FLETCHER_2 },
- { "fletcher4", ZIO_CHECKSUM_FLETCHER_4 },
- { "sha256", ZIO_CHECKSUM_SHA256 },
- { NULL }
-};
-
-struct {
- const char *name;
- uint64_t value;
-} compress_table[] = {
- { "on", ZIO_COMPRESS_ON },
- { "off", ZIO_COMPRESS_OFF },
- { "lzjb", ZIO_COMPRESS_LZJB },
- { NULL }
-};
-
-struct {
- const char *name;
- uint64_t value;
-} snapdir_table[] = {
- { "hidden", ZFS_SNAPDIR_HIDDEN },
- { "visible", ZFS_SNAPDIR_VISIBLE },
- { NULL }
-};
-
-struct {
- const char *name;
- uint64_t value;
-} acl_mode_table[] = {
- { "discard", DISCARD },
- { "groupmask", GROUPMASK },
- { "passthrough", PASSTHROUGH },
- { NULL }
-};
-
-struct {
- const char *name;
- uint64_t value;
-} acl_inherit_table[] = {
- { "discard", DISCARD },
- { "noallow", NOALLOW },
- { "secure", SECURE },
- { "passthrough", PASSTHROUGH },
- { NULL }
-};
-
-
/*
* Given a numeric suffix, convert the value into a number of bits that the
* resulting value must be shifted.
@@ -541,272 +520,496 @@ nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num)
}
int
-zfs_nicestrtonum(const char *str, uint64_t *val)
+zfs_nicestrtonum(libzfs_handle_t *hdl, const char *str, uint64_t *val)
{
- return (nicestrtonum(NULL, str, val));
+ return (nicestrtonum(hdl, str, val));
}
/*
- * Given a property type and value, verify that the value is appropriate. Used
- * by zfs_prop_set() and some libzfs consumers.
+ * The prop_parse_*() functions are designed to allow flexibility in callers
+ * when setting properties. At the DSL layer, all properties are either 64-bit
+ * numbers or strings. We want the user to be able to ignore this fact and
+ * specify properties as native values (boolean, for example) or as strings (to
+ * simplify command line utilities). This also handles converting index types
+ * (compression, checksum, etc) from strings to their on-disk index.
*/
-int
-zfs_prop_validate(libzfs_handle_t *hdl, zfs_prop_t prop, const char *value,
- uint64_t *intval)
-{
- const char *propname = zfs_prop_to_name(prop);
- uint64_t number;
- char errbuf[1024];
- int i;
- /*
- * Check to see if this a read-only property.
- */
- if (zfs_prop_readonly(prop))
- return (zfs_error(hdl, EZFS_PROPREADONLY,
- dgettext(TEXT_DOMAIN, "cannot set %s property"), propname));
+static int
+prop_parse_boolean(libzfs_handle_t *hdl, nvpair_t *elem, uint64_t *val)
+{
+ uint64_t ret;
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "bad %s value '%s'"), propname, value);
+ switch (nvpair_type(elem)) {
+ case DATA_TYPE_STRING:
+ {
+ char *value;
+ VERIFY(nvpair_value_string(elem, &value) == 0);
- /* See if the property value is too long */
- if (strlen(value) >= ZFS_MAXPROPLEN) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "value is too long"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
- }
+ if (strcmp(value, "on") == 0) {
+ ret = 1;
+ } else if (strcmp(value, "off") == 0) {
+ ret = 0;
+ } else {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property '%s' must be 'on' or 'off'"),
+ nvpair_name(elem));
+ return (-1);
+ }
+ break;
+ }
- /* Perform basic checking based on property type */
- switch (zfs_prop_get_type(prop)) {
- case prop_type_boolean:
- if (strcmp(value, "on") == 0) {
- number = 1;
- } else if (strcmp(value, "off") == 0) {
- number = 0;
- } else {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "must be 'on' or 'off'"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ case DATA_TYPE_UINT64:
+ {
+ VERIFY(nvpair_value_uint64(elem, &ret) == 0);
+ if (ret > 1) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a boolean value"),
+ nvpair_name(elem));
+ return (-1);
+ }
+ break;
}
- break;
- case prop_type_number:
- /* treat 'none' as 0 */
- if (strcmp(value, "none") == 0) {
- number = 0;
+ case DATA_TYPE_BOOLEAN_VALUE:
+ {
+ boolean_t value;
+ VERIFY(nvpair_value_boolean_value(elem, &value) == 0);
+ ret = value;
break;
}
- if (nicestrtonum(hdl, value, &number) != 0)
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ default:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a boolean value"),
+ nvpair_name(elem));
+ return (-1);
+ }
- /* don't allow 0 for quota, use 'none' instead */
- if (prop == ZFS_PROP_QUOTA && number == 0 &&
- strcmp(value, "none") != 0) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "use 'quota=none' to disable"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
- }
+ *val = ret;
+ return (0);
+}
- /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */
- if (prop == ZFS_PROP_RECORDSIZE ||
- prop == ZFS_PROP_VOLBLOCKSIZE) {
- if (number < SPA_MINBLOCKSIZE ||
- number > SPA_MAXBLOCKSIZE || !ISP2(number)) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "must be power of 2 from %u to %uk"),
- (uint_t)SPA_MINBLOCKSIZE,
- (uint_t)SPA_MAXBLOCKSIZE >> 10);
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+static int
+prop_parse_number(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop,
+ uint64_t *val)
+{
+ uint64_t ret;
+ boolean_t isnone = B_FALSE;
+
+ switch (nvpair_type(elem)) {
+ case DATA_TYPE_STRING:
+ {
+ char *value;
+ (void) nvpair_value_string(elem, &value);
+ if (strcmp(value, "none") == 0) {
+ isnone = B_TRUE;
+ ret = 0;
+ } else if (nicestrtonum(hdl, value, &ret) != 0) {
+ return (-1);
}
+ break;
}
+ case DATA_TYPE_UINT64:
+ (void) nvpair_value_uint64(elem, &ret);
break;
- case prop_type_string:
- case prop_type_index:
+ default:
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a number"),
+ nvpair_name(elem));
+ return (-1);
+ }
+
+ /*
+ * Quota special: force 'none' and don't allow 0.
+ */
+ if (ret == 0 && !isnone && prop == ZFS_PROP_QUOTA) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "use 'none' to disable quota"));
+ return (-1);
+ }
+
+ *val = ret;
+ return (0);
+}
+
+static int
+prop_parse_index(libzfs_handle_t *hdl, nvpair_t *elem, zfs_prop_t prop,
+ uint64_t *val)
+{
+ char *propname = nvpair_name(elem);
+ char *value;
+
+ if (nvpair_type(elem) != DATA_TYPE_STRING) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a string"), propname);
+ return (-1);
+ }
+
+ (void) nvpair_value_string(elem, &value);
+
+ if (zfs_prop_string_to_index(prop, value, val) != 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be one of '%s'"), propname,
+ zfs_prop_values(prop));
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Given an nvlist of properties to set, validates that they are correct, and
+ * parses any numeric properties (index, boolean, etc) if they are specified as
+ * strings.
+ */
+static nvlist_t *
+zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
+ uint64_t zoned, zfs_handle_t *zhp, const char *errbuf)
+{
+ nvpair_t *elem;
+ const char *propname;
+ zfs_prop_t prop;
+ uint64_t intval;
+ char *strval;
+ nvlist_t *ret;
+
+ if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
+ (void) no_memory(hdl);
+ return (NULL);
+ }
+
+ if (type == ZFS_TYPE_SNAPSHOT) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "snaphot properties cannot be modified"));
+ (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
+ goto error;
+ }
+
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
+ propname = nvpair_name(elem);
+
/*
- * The two writable string values, 'mountpoint' and
- * 'checksum' need special consideration. The 'index' types are
- * specified as strings by the user, but passed to the kernel as
- * integers.
+ * Make sure this property is valid and applies to this type.
*/
- switch (prop) {
- case ZFS_PROP_MOUNTPOINT:
- if (strcmp(value, ZFS_MOUNTPOINT_NONE) == 0 ||
- strcmp(value, ZFS_MOUNTPOINT_LEGACY) == 0)
- break;
-
- if (value[0] != '/') {
+ if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) {
+ if (!zfs_prop_user(propname)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "must be an absolute path, 'none', or "
- "'legacy'"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
- }
- break;
+ "invalid property '%s'"),
+ propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ } else {
+ /*
+ * If this is a user property, make sure it's a
+ * string, and that it's less than
+ * ZAP_MAXNAMELEN.
+ */
+ if (nvpair_type(elem) != DATA_TYPE_STRING) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a string"),
+ propname);
+ (void) zfs_error(hdl, EZFS_BADPROP,
+ errbuf);
+ goto error;
+ }
- case ZFS_PROP_CHECKSUM:
- for (i = 0; checksum_table[i].name != NULL; i++) {
- if (strcmp(value, checksum_table[i].name)
- == 0) {
- number = checksum_table[i].value;
- break;
+ if (strlen(nvpair_name(elem)) >=
+ ZAP_MAXNAMELEN) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "property name '%s' is too long"),
+ propname);
+ (void) zfs_error(hdl, EZFS_BADPROP,
+ errbuf);
+ goto error;
}
}
- if (checksum_table[i].name == NULL) {
+ (void) nvpair_value_string(elem, &strval);
+ if (nvlist_add_string(ret, propname, strval) != 0) {
+ (void) no_memory(hdl);
+ goto error;
+ }
+ continue;
+ }
+
+ /*
+ * Normalize the name, to get rid of shorthand abbrevations.
+ */
+ propname = zfs_prop_to_name(prop);
+
+ if (!zfs_prop_valid_for_type(prop, type)) {
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN, "'%s' does not "
+ "apply to datasets of this type"), propname);
+ (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
+ goto error;
+ }
+
+ if (zfs_prop_readonly(prop) &&
+ (prop != ZFS_PROP_VOLBLOCKSIZE || zhp != NULL)) {
+ zfs_error_aux(hdl,
+ dgettext(TEXT_DOMAIN, "'%s' is readonly"),
+ propname);
+ (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
+ goto error;
+ }
+
+ /*
+ * Convert any properties to the internal DSL value types.
+ */
+ strval = NULL;
+ switch (zfs_prop_get_type(prop)) {
+ case prop_type_boolean:
+ if (prop_parse_boolean(hdl, elem, &intval) != 0) {
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ break;
+
+ case prop_type_string:
+ if (nvpair_type(elem) != DATA_TYPE_STRING) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "must be 'on', 'off', 'fletcher2', "
- "'fletcher4', or 'sha256'"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ "'%s' must be a string"),
+ propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
+ }
+ (void) nvpair_value_string(elem, &strval);
+ if (strlen(strval) >= ZFS_MAXPROPLEN) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' is too long"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
}
break;
- case ZFS_PROP_COMPRESSION:
- for (i = 0; compress_table[i].name != NULL; i++) {
- if (strcmp(value, compress_table[i].name)
- == 0) {
- number = compress_table[i].value;
- break;
- }
+ case prop_type_number:
+ if (prop_parse_number(hdl, elem, prop, &intval) != 0) {
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
}
+ break;
- if (compress_table[i].name == NULL) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "must be 'on', 'off', or 'lzjb'"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ case prop_type_index:
+ if (prop_parse_index(hdl, elem, prop, &intval) != 0) {
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
}
break;
- case ZFS_PROP_SNAPDIR:
- for (i = 0; snapdir_table[i].name != NULL; i++) {
- if (strcmp(value, snapdir_table[i].name) == 0) {
- number = snapdir_table[i].value;
- break;
- }
+ default:
+ abort();
+ }
+
+ /*
+ * Add the result to our return set of properties.
+ */
+ if (strval) {
+ if (nvlist_add_string(ret, propname, strval) != 0) {
+ (void) no_memory(hdl);
+ goto error;
}
+ } else if (nvlist_add_uint64(ret, propname, intval) != 0) {
+ (void) no_memory(hdl);
+ goto error;
+ }
- if (snapdir_table[i].name == NULL) {
+ /*
+ * Perform some additional checks for specific properties.
+ */
+ switch (prop) {
+ case ZFS_PROP_RECORDSIZE:
+ case ZFS_PROP_VOLBLOCKSIZE:
+ /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */
+ if (intval < SPA_MINBLOCKSIZE ||
+ intval > SPA_MAXBLOCKSIZE || !ISP2(intval)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "must be 'hidden' or 'visible'"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ "'%s' must be power of 2 from %u "
+ "to %uk"), propname,
+ (uint_t)SPA_MINBLOCKSIZE,
+ (uint_t)SPA_MAXBLOCKSIZE >> 10);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
}
break;
- case ZFS_PROP_ACLMODE:
- for (i = 0; acl_mode_table[i].name != NULL; i++) {
- if (strcmp(value, acl_mode_table[i].name)
- == 0) {
- number = acl_mode_table[i].value;
- break;
- }
- }
+ case ZFS_PROP_MOUNTPOINT:
+ if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 ||
+ strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0)
+ break;
- if (acl_mode_table[i].name == NULL) {
+ if (strval[0] != '/') {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "must be 'disacard', 'groupmask', or "
- "'passthrough'"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ "'%s' must be an absolute path, "
+ "'none', or 'legacy'"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+ goto error;
}
break;
+ }
- case ZFS_PROP_ACLINHERIT:
- for (i = 0; acl_inherit_table[i].name != NULL; i++) {
- if (strcmp(value, acl_inherit_table[i].name)
- == 0) {
- number = acl_inherit_table[i].value;
- break;
+ /*
+ * For the mountpoint and sharenfs properties, check if it can
+ * be set in a global/non-global zone based on the zoned
+ * property value:
+ *
+ * global zone non-global zone
+ * -----------------------------------------------------
+ * zoned=on mountpoint (no) mountpoint (yes)
+ * sharenfs (no) sharenfs (no)
+ *
+ * zoned=off mountpoint (yes) N/A
+ * sharenfs (yes)
+ */
+ if (prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) {
+ if (zoned) {
+ if (getzoneid() == GLOBAL_ZONEID) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' cannot be set on "
+ "dataset in a non-global zone"),
+ propname);
+ (void) zfs_error(hdl, EZFS_ZONED,
+ errbuf);
+ goto error;
+ } else if (prop == ZFS_PROP_SHARENFS) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' cannot be set in "
+ "a non-global zone"), propname);
+ (void) zfs_error(hdl, EZFS_ZONED,
+ errbuf);
+ goto error;
}
+ } else if (getzoneid() != GLOBAL_ZONEID) {
+ /*
+ * If zoned property is 'off', this must be in
+ * a globle zone. If not, something is wrong.
+ */
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' cannot be set while dataset "
+ "'zoned' property is set"), propname);
+ (void) zfs_error(hdl, EZFS_ZONED, errbuf);
+ goto error;
}
+ }
- if (acl_inherit_table[i].name == NULL) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "must be 'discard, 'noallow', 'secure', "
- "or 'passthrough'"));
- return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ /*
+ * For changes to existing volumes, we have some additional
+ * checks to enforce.
+ */
+ if (type == ZFS_TYPE_VOLUME && zhp != NULL) {
+ uint64_t volsize = zfs_prop_get_int(zhp,
+ ZFS_PROP_VOLSIZE);
+ uint64_t blocksize = zfs_prop_get_int(zhp,
+ ZFS_PROP_VOLBLOCKSIZE);
+ char buf[64];
+
+ switch (prop) {
+ case ZFS_PROP_RESERVATION:
+ if (intval > volsize) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' is greater than current "
+ "volume size"), propname);
+ (void) zfs_error(hdl, EZFS_BADPROP,
+ errbuf);
+ goto error;
+ }
+ break;
+
+ case ZFS_PROP_VOLSIZE:
+ if (intval % blocksize != 0) {
+ zfs_nicenum(blocksize, buf,
+ sizeof (buf));
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' must be a multiple of "
+ "volume block size (%s)"),
+ propname, buf);
+ (void) zfs_error(hdl, EZFS_BADPROP,
+ errbuf);
+ goto error;
+ }
+
+ if (intval == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "'%s' cannot be zero"),
+ propname);
+ (void) zfs_error(hdl, EZFS_BADPROP,
+ errbuf);
+ goto error;
+ }
}
- break;
+ }
+ }
- case ZFS_PROP_SHARENFS:
- /*
- * Nothing to do for 'sharenfs', this gets passed on to
- * share(1M) verbatim.
- */
- break;
+ /*
+ * If this is an existing volume, and someone is setting the volsize,
+ * make sure that it matches the reservation, or add it if necessary.
+ */
+ if (zhp != NULL && type == ZFS_TYPE_VOLUME &&
+ nvlist_lookup_uint64(ret, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
+ &intval) == 0) {
+ uint64_t old_volsize = zfs_prop_get_int(zhp,
+ ZFS_PROP_VOLSIZE);
+ uint64_t old_reservation = zfs_prop_get_int(zhp,
+ ZFS_PROP_RESERVATION);
+ uint64_t new_reservation;
+
+ if (old_volsize == old_reservation &&
+ nvlist_lookup_uint64(ret,
+ zfs_prop_to_name(ZFS_PROP_RESERVATION),
+ &new_reservation) != 0) {
+ if (nvlist_add_uint64(ret,
+ zfs_prop_to_name(ZFS_PROP_RESERVATION),
+ intval) != 0) {
+ (void) no_memory(hdl);
+ goto error;
+ }
}
}
- if (intval != NULL)
- *intval = number;
+ return (ret);
- return (0);
+error:
+ nvlist_free(ret);
+ return (NULL);
}
/*
* Given a property name and value, set the property for the given dataset.
*/
int
-zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval)
+zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
{
- const char *propname = zfs_prop_to_name(prop);
- uint64_t number;
zfs_cmd_t zc = { 0 };
- int ret;
- prop_changelist_t *cl;
+ int ret = -1;
+ prop_changelist_t *cl = NULL;
char errbuf[1024];
libzfs_handle_t *hdl = zhp->zfs_hdl;
-
- if (zfs_prop_validate(zhp->zfs_hdl, prop, propval, &number) != 0)
- return (-1);
-
+ nvlist_t *nvl = NULL, *realprops;
+ zfs_prop_t prop;
(void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN, "cannot set %s for '%s'"), propname,
+ dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
zhp->zfs_name);
- /*
- * Check to see if the value applies to this type
- */
- if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
- return (zfs_error(hdl, EZFS_PROPTYPE, errbuf));
-
- /*
- * For the mountpoint and sharenfs properties, check if it can be set
- * in a global/non-global zone based on the zoned property value:
- *
- * global zone non-global zone
- * -----------------------------------------------------
- * zoned=on mountpoint (no) mountpoint (yes)
- * sharenfs (no) sharenfs (no)
- *
- * zoned=off mountpoint (yes) N/A
- * sharenfs (yes)
- */
- if (prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS) {
- if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
- if (getzoneid() == GLOBAL_ZONEID) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "dataset is used in a non-global zone"));
- return (zfs_error(hdl, EZFS_ZONED, errbuf));
- } else if (prop == ZFS_PROP_SHARENFS) {
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "filesystems cannot be shared in a "
- "non-global zone"));
- return (zfs_error(hdl, EZFS_ZONED, errbuf));
- }
- } else if (getzoneid() != GLOBAL_ZONEID) {
- /*
- * If zoned property is 'off', this must be in
- * a globle zone. If not, something is wrong.
- */
- zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "dataset is used in a non-global zone, but "
- "'zoned' property is not set"));
- return (zfs_error(hdl, EZFS_ZONED, errbuf));
- }
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
+ nvlist_add_string(nvl, propname, propval) != 0) {
+ (void) no_memory(hdl);
+ goto error;
}
+ if ((realprops = zfs_validate_properties(hdl, zhp->zfs_type, nvl,
+ zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, errbuf)) == NULL)
+ goto error;
+ nvlist_free(nvl);
+ nvl = realprops;
+
+ prop = zfs_name_to_prop(propname);
+
if ((cl = changelist_gather(zhp, prop, 0)) == NULL)
- return (-1);
+ goto error;
if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@@ -824,48 +1027,10 @@ zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval)
*/
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- switch (prop) {
- case ZFS_PROP_QUOTA:
- zc.zc_cookie = number;
- ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_QUOTA, &zc);
- break;
- case ZFS_PROP_RESERVATION:
- zc.zc_cookie = number;
- ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_RESERVATION,
- &zc);
- break;
- case ZFS_PROP_MOUNTPOINT:
- case ZFS_PROP_SHARENFS:
- /*
- * These properties are passed down as real strings.
- */
- (void) strlcpy(zc.zc_prop_name, propname,
- sizeof (zc.zc_prop_name));
- (void) strlcpy(zc.zc_prop_value, propval,
- sizeof (zc.zc_prop_value));
- zc.zc_intsz = 1;
- zc.zc_numints = strlen(propval) + 1;
- ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc);
- break;
- case ZFS_PROP_VOLSIZE:
- zc.zc_volsize = number;
- ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_VOLSIZE, &zc);
- break;
- case ZFS_PROP_VOLBLOCKSIZE:
- zc.zc_volblocksize = number;
- ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_VOLBLOCKSIZE,
- &zc);
- break;
- default:
- (void) strlcpy(zc.zc_prop_name, propname,
- sizeof (zc.zc_prop_name));
- /* LINTED - alignment */
- *(uint64_t *)zc.zc_prop_value = number;
- zc.zc_intsz = 8;
- zc.zc_numints = 1;
- ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc);
- break;
- }
+ if (zcmd_write_src_nvlist(hdl, &zc, nvl, NULL) != 0)
+ goto error;
+
+ ret = ioctl(hdl->libzfs_fd, ZFS_IOC_SET_PROP, &zc);
if (ret != 0) {
switch (errno) {
@@ -900,7 +1065,7 @@ zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval)
if (prop == ZFS_PROP_VOLBLOCKSIZE)
(void) zfs_error(hdl, EZFS_VOLHASDATA, errbuf);
else
- return (zfs_standard_error(hdl, EBUSY, errbuf));
+ (void) zfs_standard_error(hdl, EBUSY, errbuf);
break;
case EROFS:
@@ -926,14 +1091,15 @@ zfs_prop_set(zfs_handle_t *zhp, zfs_prop_t prop, const char *propval)
* Refresh the statistics so the new property value
* is reflected.
*/
- if ((ret = changelist_postfix(cl)) != 0)
- goto error;
-
- (void) get_stats(zhp);
+ if ((ret = changelist_postfix(cl)) == 0)
+ (void) get_stats(zhp);
}
error:
- changelist_free(cl);
+ nvlist_free(nvl);
+ zcmd_free_nvlists(&zc);
+ if (cl)
+ changelist_free(cl);
return (ret);
}
@@ -941,18 +1107,39 @@ error:
* Given a property, inherit the value from the parent dataset.
*/
int
-zfs_prop_inherit(zfs_handle_t *zhp, zfs_prop_t prop)
+zfs_prop_inherit(zfs_handle_t *zhp, const char *propname)
{
- const char *propname = zfs_prop_to_name(prop);
zfs_cmd_t zc = { 0 };
int ret;
prop_changelist_t *cl;
libzfs_handle_t *hdl = zhp->zfs_hdl;
char errbuf[1024];
+ zfs_prop_t prop;
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot inherit %s for '%s'"), propname, zhp->zfs_name);
+ if ((prop = zfs_name_to_prop(propname)) == ZFS_PROP_INVAL) {
+ /*
+ * For user properties, the amount of work we have to do is very
+ * small, so just do it here.
+ */
+ if (!zfs_prop_user(propname)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid property"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ }
+
+ (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+ (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
+
+ if (ioctl(zhp->zfs_hdl->libzfs_fd,
+ ZFS_IOC_SET_PROP, &zc) != 0)
+ return (zfs_standard_error(hdl, errno, errbuf));
+
+ return (0);
+ }
+
/*
* Verify that this property is inheritable.
*/
@@ -969,7 +1156,7 @@ zfs_prop_inherit(zfs_handle_t *zhp, zfs_prop_t prop)
return (zfs_error(hdl, EZFS_PROPTYPE, errbuf));
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- (void) strlcpy(zc.zc_prop_name, propname, sizeof (zc.zc_prop_name));
+ (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID &&
zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
@@ -995,8 +1182,6 @@ zfs_prop_inherit(zfs_handle_t *zhp, zfs_prop_t prop)
if ((ret = changelist_prefix(cl)) != 0)
goto error;
- zc.zc_numints = 0;
-
if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd,
ZFS_IOC_SET_PROP, &zc)) != 0) {
return (zfs_standard_error(hdl, errno, errbuf));
@@ -1011,7 +1196,6 @@ zfs_prop_inherit(zfs_handle_t *zhp, zfs_prop_t prop)
(void) get_stats(zhp);
}
-
error:
changelist_free(cl);
return (ret);
@@ -1240,11 +1424,11 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src,
break;
case ZFS_PROP_VOLSIZE:
- *val = zhp->zfs_volsize;
+ *val = zhp->zfs_volstats.zv_volsize;
break;
case ZFS_PROP_VOLBLOCKSIZE:
- *val = zhp->zfs_volblocksize;
+ *val = zhp->zfs_volstats.zv_volblocksize;
break;
case ZFS_PROP_USED:
@@ -1259,6 +1443,10 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src,
*val = (zhp->zfs_mntopts != NULL);
break;
+ case ZFS_PROP_CANMOUNT:
+ *val = getprop_uint64(zhp, prop, source);
+ break;
+
default:
zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
"cannot get non-numeric property"));
@@ -1308,8 +1496,8 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
char *source = NULL;
uint64_t val;
char *str;
- int i;
const char *root;
+ const char *strval;
/*
* Check to see if this property applies to our object
@@ -1327,6 +1515,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
case ZFS_PROP_ZONED:
case ZFS_PROP_DEVICES:
case ZFS_PROP_EXEC:
+ case ZFS_PROP_CANMOUNT:
/*
* Basic boolean values are built on top of
* get_numeric_property().
@@ -1357,53 +1546,13 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
break;
case ZFS_PROP_COMPRESSION:
- val = getprop_uint64(zhp, prop, &source);
- for (i = 0; compress_table[i].name != NULL; i++) {
- if (compress_table[i].value == val)
- break;
- }
- assert(compress_table[i].name != NULL);
- (void) strlcpy(propbuf, compress_table[i].name, proplen);
- break;
-
case ZFS_PROP_CHECKSUM:
- val = getprop_uint64(zhp, prop, &source);
- for (i = 0; checksum_table[i].name != NULL; i++) {
- if (checksum_table[i].value == val)
- break;
- }
- assert(checksum_table[i].name != NULL);
- (void) strlcpy(propbuf, checksum_table[i].name, proplen);
- break;
-
case ZFS_PROP_SNAPDIR:
- val = getprop_uint64(zhp, prop, &source);
- for (i = 0; snapdir_table[i].name != NULL; i++) {
- if (snapdir_table[i].value == val)
- break;
- }
- assert(snapdir_table[i].name != NULL);
- (void) strlcpy(propbuf, snapdir_table[i].name, proplen);
- break;
-
case ZFS_PROP_ACLMODE:
- val = getprop_uint64(zhp, prop, &source);
- for (i = 0; acl_mode_table[i].name != NULL; i++) {
- if (acl_mode_table[i].value == val)
- break;
- }
- assert(acl_mode_table[i].name != NULL);
- (void) strlcpy(propbuf, acl_mode_table[i].name, proplen);
- break;
-
case ZFS_PROP_ACLINHERIT:
val = getprop_uint64(zhp, prop, &source);
- for (i = 0; acl_inherit_table[i].name != NULL; i++) {
- if (acl_inherit_table[i].value == val)
- break;
- }
- assert(acl_inherit_table[i].name != NULL);
- (void) strlcpy(propbuf, acl_inherit_table[i].name, proplen);
+ verify(zfs_prop_index_to_string(prop, val, &strval) == 0);
+ (void) strlcpy(propbuf, strval, proplen);
break;
case ZFS_PROP_CREATION:
@@ -1737,10 +1886,12 @@ parent_name(const char *path, char *buf, size_t buflen)
}
/*
- * Checks to make sure that the given path has a parent, and that it exists.
+ * Checks to make sure that the given path has a parent, and that it exists. We
+ * also fetch the 'zoned' property, which is used to validate property settings
+ * when creating new datasets.
*/
static int
-check_parents(libzfs_handle_t *hdl, const char *path)
+check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned)
{
zfs_cmd_t zc = { 0 };
char parent[ZFS_MAXNAMELEN];
@@ -1783,9 +1934,9 @@ check_parents(libzfs_handle_t *hdl, const char *path)
}
}
+ *zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
/* we are in a non-global zone, but parent is in the global zone */
- if (getzoneid() != GLOBAL_ZONEID &&
- !zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
+ if (getzoneid() != GLOBAL_ZONEID && !(*zoned)) {
(void) zfs_standard_error(hdl, EPERM, errbuf);
zfs_close(zhp);
return (-1);
@@ -1805,29 +1956,18 @@ check_parents(libzfs_handle_t *hdl, const char *path)
}
/*
- * Create a new filesystem or volume. 'sizestr' and 'blocksizestr' are used
- * only for volumes, and indicate the size and blocksize of the volume.
+ * Create a new filesystem or volume.
*/
int
zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
- const char *sizestr, const char *blocksizestr)
+ nvlist_t *props)
{
zfs_cmd_t zc = { 0 };
int ret;
uint64_t size = 0;
uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
char errbuf[1024];
-
- /* convert sizestr into integer size */
- if (sizestr != NULL && nicestrtonum(hdl, sizestr, &size) != 0)
- return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN,
- "bad volume size '%s'"), sizestr));
-
- /* convert blocksizestr into integer blocksize */
- if (blocksizestr != NULL && nicestrtonum(hdl, blocksizestr,
- &blocksize) != 0)
- return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN,
- "bad volume blocksize '%s'"), blocksizestr));
+ uint64_t zoned;
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot create '%s'"), path);
@@ -1837,7 +1977,7 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
/* validate parents exist */
- if (check_parents(hdl, path) != 0)
+ if (check_parents(hdl, path, &zoned) != 0)
return (-1);
/*
@@ -1859,6 +1999,10 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
else
zc.zc_objset_type = DMU_OST_ZFS;
+ if (props && (props = zfs_validate_properties(hdl, type, props, zoned,
+ NULL, errbuf)) == 0)
+ return (-1);
+
if (type == ZFS_TYPE_VOLUME) {
/*
* If we are creating a volume, the size and block size must
@@ -1867,43 +2011,57 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
* volsize must be a multiple of the block size, and cannot be
* zero.
*/
- if (size == 0) {
+ if (props == NULL || nvlist_lookup_uint64(props,
+ zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) {
+ nvlist_free(props);
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "cannot be zero"));
- return (zfs_error(hdl, EZFS_BADPROP,
- dgettext(TEXT_DOMAIN, "bad volume size '%s'"),
- sizestr));
+ "missing volume size"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ }
+
+ if ((ret = nvlist_lookup_uint64(props,
+ zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+ &blocksize)) != 0) {
+ if (ret == ENOENT) {
+ blocksize = zfs_prop_default_numeric(
+ ZFS_PROP_VOLBLOCKSIZE);
+ } else {
+ nvlist_free(props);
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "missing volume block size"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+ }
}
- if (blocksize < SPA_MINBLOCKSIZE ||
- blocksize > SPA_MAXBLOCKSIZE || !ISP2(blocksize)) {
+ if (size == 0) {
+ nvlist_free(props);
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "must be power of 2 from %u to %uk"),
- (uint_t)SPA_MINBLOCKSIZE,
- (uint_t)SPA_MAXBLOCKSIZE >> 10);
- return (zfs_error(hdl, EZFS_BADPROP,
- dgettext(TEXT_DOMAIN,
- "bad volume block size '%s'"), blocksizestr));
+ "volume size cannot be zero"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
if (size % blocksize != 0) {
+ nvlist_free(props);
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "must be a multiple of volume block size"));
- return (zfs_error(hdl, EZFS_BADPROP,
- dgettext(TEXT_DOMAIN, "bad volume size '%s'"),
- sizestr));
+ "volume size must be a multiple of volume block "
+ "size"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
}
-
- zc.zc_volsize = size;
- zc.zc_volblocksize = blocksize;
}
+ if (props &&
+ zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0)
+ return (-1);
+ nvlist_free(props);
+
/* create the dataset */
ret = ioctl(hdl->libzfs_fd, ZFS_IOC_CREATE, &zc);
if (ret == 0 && type == ZFS_TYPE_VOLUME)
ret = zvol_create_link(hdl, path);
+ zcmd_free_nvlists(&zc);
+
/* check for failure */
if (ret != 0) {
char parent[ZFS_MAXNAMELEN];
@@ -1922,13 +2080,12 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
case EDOM:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "must be power of 2 from %u to %uk"),
+ "volume block size must be power of 2 from "
+ "%u to %uk"),
(uint_t)SPA_MINBLOCKSIZE,
(uint_t)SPA_MAXBLOCKSIZE >> 10);
- return (zfs_error(hdl, EZFS_BADPROP,
- dgettext(TEXT_DOMAIN, "bad block size '%s'"),
- blocksizestr ? blocksizestr : "<unknown>"));
+ return (zfs_error(hdl, EZFS_BADPROP, errbuf));
#ifdef _ILP32
case EOVERFLOW:
@@ -1960,11 +2117,7 @@ zfs_destroy(zfs_handle_t *zhp)
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- /*
- * We use the check for 'zfs_volblocksize' instead of ZFS_TYPE_VOLUME
- * so that we do the right thing for snapshots of volumes.
- */
- if (zhp->zfs_volblocksize != 0) {
+ if (ZFS_IS_VOLUME(zhp)) {
if (zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name) != 0)
return (-1);
@@ -1997,9 +2150,9 @@ zfs_remove_link_cb(zfs_handle_t *zhp, void *arg)
zfs_handle_t *szhp;
char name[ZFS_MAXNAMELEN];
- (void) strcpy(name, zhp->zfs_name);
- (void) strcat(name, "@");
- (void) strcat(name, dd->snapname);
+ (void) strlcpy(name, zhp->zfs_name, sizeof (name));
+ (void) strlcat(name, "@", sizeof (name));
+ (void) strlcat(name, dd->snapname, sizeof (name));
szhp = make_dataset_handle(zhp->zfs_hdl, name);
if (szhp) {
@@ -2039,7 +2192,7 @@ zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname)
}
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- (void) strlcpy(zc.zc_prop_value, snapname, sizeof (zc.zc_prop_value));
+ (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DESTROY_SNAPS, &zc);
if (ret != 0) {
@@ -2067,13 +2220,15 @@ zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname)
* Clones the given dataset. The target must be of the same type as the source.
*/
int
-zfs_clone(zfs_handle_t *zhp, const char *target)
+zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
{
zfs_cmd_t zc = { 0 };
char parent[ZFS_MAXNAMELEN];
int ret;
char errbuf[1024];
libzfs_handle_t *hdl = zhp->zfs_hdl;
+ zfs_type_t type;
+ uint64_t zoned;
assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
@@ -2085,21 +2240,39 @@ zfs_clone(zfs_handle_t *zhp, const char *target)
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
/* validate parents exist */
- if (check_parents(zhp->zfs_hdl, target) != 0)
+ if (check_parents(hdl, target, &zoned) != 0)
return (-1);
(void) parent_name(target, parent, sizeof (parent));
/* do the clone */
- if (zhp->zfs_volblocksize != 0)
+ if (ZFS_IS_VOLUME(zhp)) {
zc.zc_objset_type = DMU_OST_ZVOL;
- else
+ type = ZFS_TYPE_FILESYSTEM;
+ } else {
zc.zc_objset_type = DMU_OST_ZFS;
+ type = ZFS_TYPE_VOLUME;
+ }
+
+ if (props) {
+ if ((props = zfs_validate_properties(hdl, type, props, zoned,
+ zhp, errbuf)) == NULL)
+ return (-1);
+
+ if (zcmd_write_src_nvlist(hdl, &zc, props, NULL) != 0) {
+ nvlist_free(props);
+ return (-1);
+ }
+
+ nvlist_free(props);
+ }
(void) strlcpy(zc.zc_name, target, sizeof (zc.zc_name));
- (void) strlcpy(zc.zc_filename, zhp->zfs_name, sizeof (zc.zc_filename));
+ (void) strlcpy(zc.zc_value, zhp->zfs_name, sizeof (zc.zc_value));
ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_CREATE, &zc);
+ zcmd_free_nvlists(&zc);
+
if (ret != 0) {
switch (errno) {
@@ -2127,7 +2300,7 @@ zfs_clone(zfs_handle_t *zhp, const char *target)
return (zfs_standard_error(zhp->zfs_hdl, errno,
errbuf));
}
- } else if (zhp->zfs_volblocksize != 0) {
+ } else if (ZFS_IS_VOLUME(zhp)) {
ret = zvol_create_link(zhp->zfs_hdl, target);
}
@@ -2153,12 +2326,12 @@ promote_snap_cb(zfs_handle_t *zhp, void *data)
return (0);
/* Remove the device link if it's a zvol. */
- if (zhp->zfs_volblocksize != 0)
+ if (ZFS_IS_VOLUME(zhp))
(void) zvol_remove_link(zhp->zfs_hdl, zhp->zfs_name);
/* Check for conflicting names */
- (void) strcpy(snapname, pd->cb_target);
- (void) strcat(snapname, strchr(zhp->zfs_name, '@'));
+ (void) strlcpy(snapname, pd->cb_target, sizeof (snapname));
+ (void) strlcat(snapname, strchr(zhp->zfs_name, '@'), sizeof (snapname));
szhp = make_dataset_handle(zhp->zfs_hdl, snapname);
if (szhp != NULL) {
zfs_close(szhp);
@@ -2181,7 +2354,7 @@ promote_snap_done_cb(zfs_handle_t *zhp, void *data)
return (0);
/* Create the device link if it's a zvol. */
- if (zhp->zfs_volblocksize != 0)
+ if (ZFS_IS_VOLUME(zhp))
(void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name);
return (0);
@@ -2211,7 +2384,7 @@ zfs_promote(zfs_handle_t *zhp)
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
}
- (void) strcpy(parent, zhp->zfs_dmustats.dds_clone_of);
+ (void) strlcpy(parent, zhp->zfs_dmustats.dds_clone_of, sizeof (parent));
if (parent[0] == '\0') {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"not a cloned filesystem"));
@@ -2240,8 +2413,8 @@ zfs_promote(zfs_handle_t *zhp)
}
/* issue the ioctl */
- (void) strlcpy(zc.zc_prop_value, zhp->zfs_dmustats.dds_clone_of,
- sizeof (zc.zc_prop_value));
+ (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_clone_of,
+ sizeof (zc.zc_value));
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
ret = ioctl(hdl->libzfs_fd, ZFS_IOC_PROMOTE, &zc);
@@ -2278,13 +2451,14 @@ static int
zfs_create_link_cb(zfs_handle_t *zhp, void *arg)
{
char *snapname = arg;
+ int ret;
if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
char name[MAXPATHLEN];
- (void) strcpy(name, zhp->zfs_name);
- (void) strcat(name, "@");
- (void) strcat(name, snapname);
+ (void) strlcpy(name, zhp->zfs_name, sizeof (name));
+ (void) strlcat(name, "@", sizeof (name));
+ (void) strlcat(name, snapname, sizeof (name));
(void) zvol_create_link(zhp->zfs_hdl, name);
/*
* NB: this is simply a best-effort. We don't want to
@@ -2292,7 +2466,12 @@ zfs_create_link_cb(zfs_handle_t *zhp, void *arg)
* the volumes.
*/
}
- return (zfs_iter_filesystems(zhp, zfs_create_link_cb, snapname));
+
+ ret = zfs_iter_filesystems(zhp, zfs_create_link_cb, snapname);
+
+ zfs_close(zhp);
+
+ return (ret);
}
/*
@@ -2329,7 +2508,7 @@ zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive)
}
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- (void) strlcpy(zc.zc_prop_value, delim+1, sizeof (zc.zc_prop_value));
+ (void) strlcpy(zc.zc_value, delim+1, sizeof (zc.zc_value));
zc.zc_cookie = recursive;
ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SNAPSHOT, &zc);
@@ -2338,7 +2517,7 @@ zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive)
* zc.zc_name.
*/
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
- "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_prop_value);
+ "cannot create snapshot '%s@%s'"), zc.zc_name, zc.zc_value);
if (ret == 0 && recursive) {
(void) zfs_iter_filesystems(zhp,
zfs_create_link_cb, (char *)delim+1);
@@ -2377,10 +2556,10 @@ zfs_send(zfs_handle_t *zhp_to, zfs_handle_t *zhp_from)
/* do the ioctl() */
(void) strlcpy(zc.zc_name, zhp_to->zfs_name, sizeof (zc.zc_name));
if (zhp_from) {
- (void) strlcpy(zc.zc_prop_value, zhp_from->zfs_name,
+ (void) strlcpy(zc.zc_value, zhp_from->zfs_name,
sizeof (zc.zc_name));
} else {
- zc.zc_prop_value[0] = '\0';
+ zc.zc_value[0] = '\0';
}
zc.zc_cookie = STDOUT_FILENO;
@@ -2437,7 +2616,7 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix,
"cannot receive"));
/* trim off snapname, if any */
- (void) strcpy(zc.zc_name, tosnap);
+ (void) strlcpy(zc.zc_name, tosnap, sizeof (zc.zc_name));
cp = strchr(zc.zc_name, '@');
if (cp)
*cp = '\0';
@@ -2477,7 +2656,7 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix,
/*
* Determine name of destination snapshot.
*/
- (void) strcpy(zc.zc_filename, tosnap);
+ (void) strlcpy(zc.zc_value, tosnap, sizeof (zc.zc_value));
if (isprefix) {
if (strchr(tosnap, '@') != NULL) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@@ -2491,8 +2670,8 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix,
else
cp++;
- (void) strcat(zc.zc_filename, "/");
- (void) strcat(zc.zc_filename, cp);
+ (void) strcat(zc.zc_value, "/");
+ (void) strcat(zc.zc_value, cp);
} else if (strchr(tosnap, '@') == NULL) {
/*
* they specified just a filesystem; tack on the
@@ -2501,7 +2680,7 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix,
cp = strchr(drr.drr_u.drr_begin.drr_toname, '@');
if (cp == NULL || strlen(tosnap) + strlen(cp) >= MAXNAMELEN)
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
- (void) strcat(zc.zc_filename, cp);
+ (void) strcat(zc.zc_value, cp);
}
if (drrb->drr_fromguid) {
@@ -2509,7 +2688,7 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix,
/* incremental backup stream */
/* do the ioctl to the containing fs */
- (void) strcpy(zc.zc_name, zc.zc_filename);
+ (void) strlcpy(zc.zc_name, zc.zc_value, sizeof (zc.zc_name));
cp = strchr(zc.zc_name, '@');
*cp = '\0';
@@ -2540,7 +2719,7 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix,
} else {
/* full backup stream */
- (void) strcpy(zc.zc_name, zc.zc_filename);
+ (void) strlcpy(zc.zc_name, zc.zc_value, sizeof (zc.zc_name));
/* make sure they aren't trying to receive into the root */
if (strchr(zc.zc_name, '/') == NULL) {
@@ -2577,7 +2756,7 @@ zfs_receive(libzfs_handle_t *hdl, const char *tosnap, int isprefix,
opname = dgettext(TEXT_DOMAIN, "create");
if (zfs_create(hdl, zc.zc_name,
- ZFS_TYPE_FILESYSTEM, NULL, NULL) != 0) {
+ ZFS_TYPE_FILESYSTEM, NULL) != 0) {
if (errno == EEXIST)
continue;
goto ancestorerr;
@@ -2623,16 +2802,14 @@ ancestorerr:
*cp = '\0';
}
- (void) strcpy(zc.zc_prop_value, tosnap);
zc.zc_cookie = STDIN_FILENO;
- zc.zc_intsz = isprefix;
- zc.zc_numints = force;
+ zc.zc_guid = force;
if (verbose) {
(void) printf("%s %s stream of %s into %s\n",
dryrun ? "would receive" : "receiving",
drrb->drr_fromguid ? "incremental" : "full",
drr.drr_u.drr_begin.drr_toname,
- zc.zc_filename);
+ zc.zc_value);
(void) fflush(stdout);
}
if (dryrun)
@@ -2655,13 +2832,13 @@ ancestorerr:
case EEXIST:
if (drrb->drr_fromguid == 0) {
/* it's the containing fs that exists */
- cp = strchr(zc.zc_filename, '@');
+ cp = strchr(zc.zc_value, '@');
*cp = '\0';
}
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"destination already exists"));
(void) zfs_error(hdl, EZFS_EXISTS, dgettext(TEXT_DOMAIN,
- "cannot restore to %s"), zc.zc_filename);
+ "cannot restore to %s"), zc.zc_value);
break;
case EINVAL:
(void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
@@ -2683,12 +2860,12 @@ ancestorerr:
* created). Also mount any children of the target filesystem
* if we did an incremental receive.
*/
- cp = strchr(zc.zc_filename, '@');
+ cp = strchr(zc.zc_value, '@');
if (cp && (ioctl_err == 0 || drrb->drr_fromguid)) {
zfs_handle_t *h;
*cp = '\0';
- h = zfs_open(hdl, zc.zc_filename,
+ h = zfs_open(hdl, zc.zc_value,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
*cp = '@';
if (h) {
@@ -2696,7 +2873,7 @@ ancestorerr:
err = zvol_create_link(hdl, h->zfs_name);
if (err == 0 && ioctl_err == 0)
err = zvol_create_link(hdl,
- zc.zc_filename);
+ zc.zc_value);
} else {
if (drrb->drr_fromguid) {
err = changelist_postfix(clp);
@@ -2794,7 +2971,7 @@ do_rollback(zfs_handle_t *zhp)
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- if (zhp->zfs_volblocksize != 0)
+ if (ZFS_IS_VOLUME(zhp))
zc.zc_objset_type = DMU_OST_ZVOL;
else
zc.zc_objset_type = DMU_OST_ZFS;
@@ -2973,8 +3150,10 @@ zfs_rename(zfs_handle_t *zhp, const char *target)
} else {
if (!zfs_validate_name(hdl, target, zhp->zfs_type))
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+ uint64_t unused;
+
/* validate parents */
- if (check_parents(hdl, target) != 0)
+ if (check_parents(hdl, target, &unused) != 0)
return (-1);
(void) parent_name(target, parent, sizeof (parent));
@@ -3015,21 +3194,20 @@ zfs_rename(zfs_handle_t *zhp, const char *target)
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"child dataset with inherited mountpoint is used "
"in a non-global zone"));
- ret = zfs_error(hdl, EZFS_ZONED, errbuf);
+ (void) zfs_error(hdl, EZFS_ZONED, errbuf);
goto error;
}
if ((ret = changelist_prefix(cl)) != 0)
goto error;
- if (zhp->zfs_volblocksize != 0)
+ if (ZFS_IS_VOLUME(zhp))
zc.zc_objset_type = DMU_OST_ZVOL;
else
zc.zc_objset_type = DMU_OST_ZFS;
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
- (void) strlcpy(zc.zc_prop_value, target, sizeof (zc.zc_prop_value));
-
+ (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value));
if ((ret = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc)) != 0) {
(void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf);
@@ -3128,3 +3306,259 @@ zvol_remove_link(libzfs_handle_t *hdl, const char *dataset)
return (0);
}
+
+nvlist_t *
+zfs_get_user_props(zfs_handle_t *zhp)
+{
+ return (zhp->zfs_user_props);
+}
+
+/*
+ * Given a comma-separated list of properties, contruct a property list
+ * containing both user-defined and native properties. This function will
+ * return a NULL list if 'all' is specified, which can later be expanded on a
+ * per-dataset basis by zfs_expand_proplist().
+ */
+int
+zfs_get_proplist(libzfs_handle_t *hdl, char *fields, zfs_proplist_t **listp)
+{
+ int i;
+ size_t len;
+ char *s, *p;
+ char c;
+ zfs_prop_t prop;
+ zfs_proplist_t *entry;
+ zfs_proplist_t **last;
+
+ *listp = NULL;
+ last = listp;
+
+ /*
+ * If 'all' is specified, return a NULL list.
+ */
+ if (strcmp(fields, "all") == 0)
+ return (0);
+
+ /*
+ * If no fields were specified, return an error.
+ */
+ if (fields[0] == '\0') {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "no properties specified"));
+ return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN,
+ "bad property list")));
+ }
+
+ /*
+ * It would be nice to use getsubopt() here, but the inclusion of column
+ * aliases makes this more effort than it's worth.
+ */
+ s = fields;
+ while (*s != '\0') {
+ if ((p = strchr(s, ',')) == NULL) {
+ len = strlen(s);
+ p = s + len;
+ } else {
+ len = p - s;
+ }
+
+ /*
+ * Check for empty options.
+ */
+ if (len == 0) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "empty property name"));
+ return (zfs_error(hdl, EZFS_BADPROP,
+ dgettext(TEXT_DOMAIN, "bad property list")));
+ }
+
+ /*
+ * Check all regular property names.
+ */
+ c = s[len];
+ s[len] = '\0';
+ for (i = 0; i < ZFS_NPROP_ALL; i++) {
+ if ((prop = zfs_name_to_prop(s)) != ZFS_PROP_INVAL)
+ break;
+ }
+
+ /*
+ * If no column is specified, and this isn't a user property,
+ * return failure.
+ */
+ if (i == ZFS_NPROP_ALL && !zfs_prop_user(s)) {
+ zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+ "invalid property '%s'"), s);
+ return (zfs_error(hdl, EZFS_BADPROP,
+ dgettext(TEXT_DOMAIN, "bad property list")));
+ }
+
+ if ((entry = zfs_alloc(hdl, sizeof (zfs_proplist_t))) == NULL)
+ return (-1);
+
+ entry->pl_prop = prop;
+ if (prop == ZFS_PROP_INVAL) {
+ if ((entry->pl_user_prop =
+ zfs_strdup(hdl, s)) == NULL) {
+ free(entry);
+ return (-1);
+ }
+ entry->pl_width = strlen(s);
+ } else {
+ entry->pl_width = zfs_prop_width(prop,
+ &entry->pl_fixed);
+ }
+
+ *last = entry;
+ last = &entry->pl_next;
+
+ s = p;
+ if (c == ',')
+ s++;
+ }
+
+ return (0);
+}
+
+void
+zfs_free_proplist(zfs_proplist_t *pl)
+{
+ zfs_proplist_t *next;
+
+ while (pl != NULL) {
+ next = pl->pl_next;
+ free(pl->pl_user_prop);
+ free(pl);
+ pl = next;
+ }
+}
+
+/*
+ * This function is used by 'zfs list' to determine the exact set of columns to
+ * display, and their maximum widths. This does two main things:
+ *
+ * - If this is a list of all properties, then expand the list to include
+ * all native properties, and set a flag so that for each dataset we look
+ * for new unique user properties and add them to the list.
+ *
+ * - For non fixed-width properties, keep track of the maximum width seen
+ * so that we can size the column appropriately.
+ */
+int
+zfs_expand_proplist(zfs_handle_t *zhp, zfs_proplist_t **plp)
+{
+ libzfs_handle_t *hdl = zhp->zfs_hdl;
+ zfs_prop_t prop;
+ zfs_proplist_t *entry;
+ zfs_proplist_t **last, **start;
+ nvlist_t *userprops, *propval;
+ nvpair_t *elem;
+ char *strval;
+ char buf[ZFS_MAXPROPLEN];
+
+ if (*plp == NULL) {
+ /*
+ * If this is the very first time we've been called for an 'all'
+ * specification, expand the list to include all native
+ * properties.
+ */
+ last = plp;
+ for (prop = 0; prop < ZFS_NPROP_VISIBLE; prop++) {
+ if ((entry = zfs_alloc(hdl,
+ sizeof (zfs_proplist_t))) == NULL)
+ return (-1);
+
+ entry->pl_prop = prop;
+ entry->pl_width = zfs_prop_width(prop,
+ &entry->pl_fixed);
+ entry->pl_all = B_TRUE;
+
+ *last = entry;
+ last = &entry->pl_next;
+ }
+
+ /*
+ * Add 'name' to the beginning of the list, which is handled
+ * specially.
+ */
+ if ((entry = zfs_alloc(hdl,
+ sizeof (zfs_proplist_t))) == NULL)
+ return (-1);
+
+ entry->pl_prop = ZFS_PROP_NAME;
+ entry->pl_width = zfs_prop_width(ZFS_PROP_NAME,
+ &entry->pl_fixed);
+ entry->pl_all = B_TRUE;
+ entry->pl_next = *plp;
+ *plp = entry;
+ }
+
+ userprops = zfs_get_user_props(zhp);
+
+ entry = *plp;
+ if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) {
+ /*
+ * Go through and add any user properties as necessary. We
+ * start by incrementing our list pointer to the first
+ * non-native property.
+ */
+ start = plp;
+ while (*start != NULL) {
+ if ((*start)->pl_prop == ZFS_PROP_INVAL)
+ break;
+ start = &(*start)->pl_next;
+ }
+
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) {
+ /*
+ * See if we've already found this property in our list.
+ */
+ for (last = start; *last != NULL;
+ last = &(*last)->pl_next) {
+ if (strcmp((*last)->pl_user_prop,
+ nvpair_name(elem)) == 0)
+ break;
+ }
+
+ if (*last == NULL) {
+ if ((entry = zfs_alloc(hdl,
+ sizeof (zfs_proplist_t))) == NULL ||
+ ((entry->pl_user_prop = zfs_strdup(hdl,
+ nvpair_name(elem)))) == NULL) {
+ free(entry);
+ return (-1);
+ }
+
+ entry->pl_prop = ZFS_PROP_INVAL;
+ entry->pl_width = strlen(nvpair_name(elem));
+ entry->pl_all = B_TRUE;
+ *last = entry;
+ }
+ }
+ }
+
+ /*
+ * Now go through and check the width of any non-fixed columns
+ */
+ for (entry = *plp; entry != NULL; entry = entry->pl_next) {
+ if (entry->pl_fixed)
+ continue;
+
+ if (entry->pl_prop != ZFS_PROP_INVAL) {
+ if (zfs_prop_get(zhp, entry->pl_prop,
+ buf, sizeof (buf), NULL, NULL, 0, B_FALSE) == 0) {
+ if (strlen(buf) > entry->pl_width)
+ entry->pl_width = strlen(buf);
+ }
+ } else if (nvlist_lookup_nvlist(userprops,
+ entry->pl_user_prop, &propval) == 0) {
+ verify(nvlist_lookup_string(propval,
+ ZFS_PROP_VALUE, &strval) == 0);
+ if (strlen(strval) > entry->pl_width)
+ entry->pl_width = strlen(strval);
+ }
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/libzfs/common/libzfs_graph.c b/usr/src/lib/libzfs/common/libzfs_graph.c
index 8ea76e51a6..c283016df7 100644
--- a/usr/src/lib/libzfs/common/libzfs_graph.c
+++ b/usr/src/lib/libzfs/common/libzfs_graph.c
@@ -207,18 +207,15 @@ zfs_vertex_add_edge(libzfs_handle_t *hdl, zfs_vertex_t *zvp,
return (-1);
if (zvp->zv_edgecount == zvp->zv_edgealloc) {
- zfs_edge_t **newedges = zfs_alloc(hdl, zvp->zv_edgealloc * 2 *
- sizeof (void *));
+ void *ptr;
- if (newedges == NULL)
+ if ((ptr = zfs_realloc(hdl, zvp->zv_edges,
+ zvp->zv_edgealloc * sizeof (void *),
+ zvp->zv_edgealloc * 2 * sizeof (void *))) == NULL)
return (-1);
- bcopy(zvp->zv_edges, newedges,
- zvp->zv_edgealloc * sizeof (void *));
-
+ zvp->zv_edges = ptr;
zvp->zv_edgealloc *= 2;
- free(zvp->zv_edges);
- zvp->zv_edges = newedges;
}
zvp->zv_edges[zvp->zv_edgecount++] = zep;
diff --git a/usr/src/lib/libzfs/common/libzfs_impl.h b/usr/src/lib/libzfs/common/libzfs_impl.h
index 3e0f737a4b..e4bc794cd8 100644
--- a/usr/src/lib/libzfs/common/libzfs_impl.h
+++ b/usr/src/lib/libzfs/common/libzfs_impl.h
@@ -60,14 +60,20 @@ struct zfs_handle {
char zfs_name[ZFS_MAXNAMELEN];
zfs_type_t zfs_type;
dmu_objset_stats_t zfs_dmustats;
+ zvol_stats_t zfs_volstats;
nvlist_t *zfs_props;
- uint64_t zfs_volsize;
- uint64_t zfs_volblocksize;
+ nvlist_t *zfs_user_props;
boolean_t zfs_mntcheck;
char *zfs_mntopts;
char zfs_root[MAXPATHLEN];
};
+/*
+ * This is different from checking zfs_type, because it will also catch
+ * snapshots of volumes.
+ */
+#define ZFS_IS_VOLUME(zhp) ((zhp)->zfs_volstats.zv_volblocksize != 0)
+
struct zpool_handle {
libzfs_handle_t *zpool_hdl;
char zpool_name[ZPOOL_MAXNAMELEN];
@@ -82,6 +88,7 @@ struct zpool_handle {
int zfs_error(libzfs_handle_t *, int, const char *, ...);
void zfs_error_aux(libzfs_handle_t *, const char *, ...);
void *zfs_alloc(libzfs_handle_t *, size_t);
+void *zfs_realloc(libzfs_handle_t *, void *, size_t, size_t);
char *zfs_strdup(libzfs_handle_t *, const char *);
int no_memory(libzfs_handle_t *);
@@ -93,6 +100,12 @@ int get_dependents(libzfs_handle_t *, boolean_t, const char *, char ***,
typedef struct prop_changelist prop_changelist_t;
+int zcmd_alloc_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *, size_t);
+int zcmd_write_src_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t *, size_t *);
+int zcmd_expand_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *);
+int zcmd_read_dst_nvlist(libzfs_handle_t *, zfs_cmd_t *, nvlist_t **);
+void zcmd_free_nvlists(zfs_cmd_t *);
+
int changelist_prefix(prop_changelist_t *);
int changelist_postfix(prop_changelist_t *);
void changelist_rename(prop_changelist_t *, const char *, const char *);
diff --git a/usr/src/lib/libzfs/common/libzfs_import.c b/usr/src/lib/libzfs/common/libzfs_import.c
index 6b76b2922c..ea74079bee 100644
--- a/usr/src/lib/libzfs/common/libzfs_import.c
+++ b/usr/src/lib/libzfs/common/libzfs_import.c
@@ -382,7 +382,6 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl)
char *name;
zfs_cmd_t zc = { 0 };
uint64_t version, guid;
- char *packed;
size_t len;
int err;
uint_t children = 0;
@@ -575,50 +574,38 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl)
/*
* Try to do the import in order to get vdev state.
*/
- if ((err = nvlist_size(config, &len, NV_ENCODE_NATIVE)) != 0)
- goto nomem;
-
- if ((packed = zfs_alloc(hdl, len)) == NULL)
- goto nomem;
-
- if ((err = nvlist_pack(config, &packed, &len,
- NV_ENCODE_NATIVE, 0)) != 0)
- goto nomem;
+ if (zcmd_write_src_nvlist(hdl, &zc, config, &len) != 0)
+ goto error;
nvlist_free(config);
config = NULL;
- zc.zc_config_src_size = len;
- zc.zc_config_src = (uint64_t)(uintptr_t)packed;
-
- zc.zc_config_dst_size = 2 * len;
- if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
- zfs_alloc(hdl, zc.zc_config_dst_size)) == NULL)
- goto nomem;
+ if (zcmd_alloc_dst_nvlist(hdl, &zc, len * 2) != 0) {
+ zcmd_free_nvlists(&zc);
+ goto error;
+ }
while ((err = ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_TRYIMPORT,
&zc)) != 0 && errno == ENOMEM) {
- free((void *)(uintptr_t)zc.zc_config_dst);
- if ((zc.zc_config_dst = (uint64_t)(uintptr_t)
- zfs_alloc(hdl, zc.zc_config_dst_size)) == NULL)
- goto nomem;
+ if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+ zcmd_free_nvlists(&zc);
+ goto error;
+ }
}
- free(packed);
-
if (err) {
(void) zpool_standard_error(hdl, errno,
dgettext(TEXT_DOMAIN, "cannot discover pools"));
- free((void *)(uintptr_t)zc.zc_config_dst);
+ zcmd_free_nvlists(&zc);
goto error;
}
- if (nvlist_unpack((void *)(uintptr_t)zc.zc_config_dst,
- zc.zc_config_dst_size, &config, 0) != 0) {
- free((void *)(uintptr_t)zc.zc_config_dst);
- goto nomem;
+ if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
+ zcmd_free_nvlists(&zc);
+ goto error;
}
- free((void *)(uintptr_t)zc.zc_config_dst);
+
+ zcmd_free_nvlists(&zc);
/*
* Go through and update the paths for spares, now that we have
@@ -640,6 +627,8 @@ get_configs(libzfs_handle_t *hdl, pool_list_t *pl)
/*
* Add this pool to the list of configs.
*/
+ verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
+ &name) == 0);
if (nvlist_add_nvlist(ret, name, config) != 0)
goto nomem;
diff --git a/usr/src/lib/libzfs/common/libzfs_mount.c b/usr/src/lib/libzfs/common/libzfs_mount.c
index 9a18777d4a..32c3191d46 100644
--- a/usr/src/lib/libzfs/common/libzfs_mount.c
+++ b/usr/src/lib/libzfs/common/libzfs_mount.c
@@ -151,6 +151,40 @@ zfs_is_mounted(zfs_handle_t *zhp, char **where)
}
/*
+ * Returns true if the given dataset is mountable, false otherwise. Returns the
+ * mountpoint in 'buf'.
+ */
+static boolean_t
+zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
+ zfs_source_t *source)
+{
+ char sourceloc[ZFS_MAXNAMELEN];
+ zfs_source_t sourcetype;
+
+ if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type))
+ return (B_FALSE);
+
+ verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen,
+ &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0);
+
+ if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 ||
+ strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0)
+ return (B_FALSE);
+
+ if (!zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT))
+ return (B_FALSE);
+
+ if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) &&
+ getzoneid() == GLOBAL_ZONEID)
+ return (B_FALSE);
+
+ if (source)
+ *source = sourcetype;
+
+ return (B_TRUE);
+}
+
+/*
* Mount the given filesystem.
*/
int
@@ -166,22 +200,7 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
else
(void) strlcpy(mntopts, options, sizeof (mntopts));
- /* ignore non-filesystems */
- if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
- sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0)
- return (0);
-
- /* return success if there is no mountpoint set */
- if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
- strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0)
- return (0);
-
- /*
- * If the 'zoned' property is set, and we're in the global zone, simply
- * return success.
- */
- if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) &&
- getzoneid() == GLOBAL_ZONEID)
+ if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
return (0);
/* Create the directory if it doesn't already exist */
@@ -334,15 +353,7 @@ zfs_share(zfs_handle_t *zhp)
FILE *fp;
libzfs_handle_t *hdl = zhp->zfs_hdl;
- /* ignore non-filesystems */
- if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM)
- return (0);
-
- /* return success if there is no mountpoint set */
- if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
- mountpoint, sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0 ||
- strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
- strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0)
+ if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
return (0);
/* return success if there are no share options */
@@ -352,14 +363,12 @@ zfs_share(zfs_handle_t *zhp)
return (0);
/*
- * If the 'zoned' property is set, simply return success since:
- * 1. in a global zone, a dataset should not be shared if it's
- * managed in a local zone.
- * 2. in a local zone, NFS server is not available.
+ * If the 'zoned' property is set, then zfs_is_mountable() will have
+ * already bailed out if we are in the global zone. But local
+ * zones cannot be NFS servers, so we ignore it for local zones as well.
*/
- if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
+ if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
return (0);
- }
/*
* Invoke the share(1M) command. We always do this, even if it's
@@ -509,28 +518,19 @@ void
remove_mountpoint(zfs_handle_t *zhp)
{
char mountpoint[ZFS_MAXPROPLEN];
- char source[ZFS_MAXNAMELEN];
- zfs_source_t sourcetype;
- int zoneid = getzoneid();
+ zfs_source_t source;
- /* ignore non-filesystems */
- if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
- sizeof (mountpoint), &sourcetype, source, sizeof (source),
- B_FALSE) != 0)
+ if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint),
+ &source))
return;
- if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0 &&
- strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
- (sourcetype == ZFS_SRC_DEFAULT ||
- sourcetype == ZFS_SRC_INHERITED) &&
- (!zfs_prop_get_int(zhp, ZFS_PROP_ZONED) ||
- zoneid != GLOBAL_ZONEID)) {
-
+ if (source == ZFS_SRC_DEFAULT ||
+ source == ZFS_SRC_INHERITED) {
/*
* Try to remove the directory, silently ignoring any errors.
* The filesystem may have since been removed or moved around,
- * and this isn't really useful to the administrator in any
- * way.
+ * and this error isn't really useful to the administrator in
+ * any way.
*/
(void) rmdir(mountpoint);
}
@@ -561,16 +561,15 @@ mount_cb(zfs_handle_t *zhp, void *data)
}
if (cbp->cb_alloc == cbp->cb_used) {
- zfs_handle_t **datasets;
+ void *ptr;
- if ((datasets = zfs_alloc(zhp->zfs_hdl, cbp->cb_alloc * 2 *
- sizeof (void *))) == NULL)
+ if ((ptr = zfs_realloc(zhp->zfs_hdl,
+ cbp->cb_datasets, cbp->cb_alloc * sizeof (void *),
+ cbp->cb_alloc * 2 * sizeof (void *))) == NULL)
return (-1);
+ cbp->cb_datasets = ptr;
- (void) memcpy(cbp->cb_datasets, datasets,
- cbp->cb_alloc * sizeof (void *));
- free(cbp->cb_datasets);
- cbp->cb_datasets = datasets;
+ cbp->cb_alloc *= 2;
}
cbp->cb_datasets[cbp->cb_used++] = zhp;
@@ -706,23 +705,19 @@ zpool_unmount_datasets(zpool_handle_t *zhp, boolean_t force)
alloc = 8;
} else {
- char **dest;
+ void *ptr;
- if ((dest = zfs_alloc(hdl,
+ if ((ptr = zfs_realloc(hdl, mountpoints,
+ alloc * sizeof (void *),
alloc * 2 * sizeof (void *))) == NULL)
goto out;
- (void) memcpy(dest, mountpoints,
- alloc * sizeof (void *));
- free(mountpoints);
- mountpoints = dest;
+ mountpoints = ptr;
- if ((dest = zfs_alloc(hdl,
+ if ((ptr = zfs_realloc(hdl, datasets,
+ alloc * sizeof (void *),
alloc * 2 * sizeof (void *))) == NULL)
goto out;
- (void) memcpy(dest, datasets,
- alloc * sizeof (void *));
- free(datasets);
- datasets = (zfs_handle_t **)dest;
+ datasets = ptr;
alloc *= 2;
}
@@ -753,8 +748,7 @@ zpool_unmount_datasets(zpool_handle_t *zhp, boolean_t force)
*/
for (i = 0; i < used; i++) {
if (is_shared(hdl, mountpoints[i]) &&
- unshare_one(hdl, datasets[i] ? datasets[i]->zfs_name :
- mountpoints[i], mountpoints[i]) != 0)
+ unshare_one(hdl, mountpoints[i], mountpoints[i]) != 0)
goto out;
}
@@ -765,7 +759,9 @@ zpool_unmount_datasets(zpool_handle_t *zhp, boolean_t force)
for (i = 0; i < used; i++) {
if (unmount_one(hdl, mountpoints[i], flags) != 0)
goto out;
+ }
+ for (i = 0; i < used; i++) {
if (datasets[i])
remove_mountpoint(datasets[i]);
}
diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c
index fd2d6cc175..35e865a151 100644
--- a/usr/src/lib/libzfs/common/libzfs_pool.c
+++ b/usr/src/lib/libzfs/common/libzfs_pool.c
@@ -344,10 +344,10 @@ zpool_get_root(zpool_handle_t *zhp, char *buf, size_t buflen)
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 ||
- zc.zc_root[0] == '\0')
+ zc.zc_value[0] == '\0')
return (-1);
- (void) strlcpy(buf, zc.zc_root, buflen);
+ (void) strlcpy(buf, zc.zc_value, buflen);
return (0);
}
@@ -371,8 +371,6 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
const char *altroot)
{
zfs_cmd_t zc = { 0 };
- char *packed;
- size_t len;
char msg[1024];
(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
@@ -385,27 +383,16 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
return (zfs_error(hdl, EZFS_BADPATH,
dgettext(TEXT_DOMAIN, "bad alternate root '%s'"), altroot));
- if (nvlist_size(nvroot, &len, NV_ENCODE_NATIVE) != 0)
- return (no_memory(hdl));
-
- if ((packed = zfs_alloc(hdl, len)) == NULL)
+ if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0)
return (-1);
- if (nvlist_pack(nvroot, &packed, &len,
- NV_ENCODE_NATIVE, 0) != 0) {
- free(packed);
- return (no_memory(hdl));
- }
-
(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
- zc.zc_config_src = (uint64_t)(uintptr_t)packed;
- zc.zc_config_src_size = len;
if (altroot != NULL)
- (void) strlcpy(zc.zc_root, altroot, sizeof (zc.zc_root));
+ (void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value));
if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CREATE, &zc) != 0) {
- free(packed);
+ zcmd_free_nvlists(&zc);
switch (errno) {
case EBUSY:
@@ -447,17 +434,18 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
}
}
- free(packed);
+ zcmd_free_nvlists(&zc);
/*
* If this is an alternate root pool, then we automatically set the
- * moutnpoint of the root dataset to be '/'.
+ * mountpoint of the root dataset to be '/'.
*/
if (altroot != NULL) {
zfs_handle_t *zhp;
verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_ANY)) != NULL);
- verify(zfs_prop_set(zhp, ZFS_PROP_MOUNTPOINT, "/") == 0);
+ verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
+ "/") == 0);
zfs_close(zhp);
}
@@ -519,9 +507,7 @@ zpool_destroy(zpool_handle_t *zhp)
int
zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
{
- char *packed;
- size_t len;
- zfs_cmd_t zc;
+ zfs_cmd_t zc = { 0 };
int ret;
libzfs_handle_t *hdl = zhp->zpool_hdl;
char msg[1024];
@@ -539,16 +525,9 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
return (zfs_error(hdl, EZFS_BADVERSION, msg));
}
- verify(nvlist_size(nvroot, &len, NV_ENCODE_NATIVE) == 0);
-
- if ((packed = zfs_alloc(zhp->zpool_hdl, len)) == NULL)
+ if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0)
return (-1);
-
- verify(nvlist_pack(nvroot, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);
-
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- zc.zc_config_src = (uint64_t)(uintptr_t)packed;
- zc.zc_config_src_size = len;
if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ADD, &zc) != 0) {
switch (errno) {
@@ -598,7 +577,7 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
ret = 0;
}
- free(packed);
+ zcmd_free_nvlists(&zc);
return (ret);
}
@@ -635,9 +614,7 @@ int
zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
const char *altroot)
{
- zfs_cmd_t zc;
- char *packed;
- size_t len;
+ zfs_cmd_t zc = { 0 };
char *thename;
char *origname;
int ret;
@@ -663,23 +640,16 @@ zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
(void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name));
if (altroot != NULL)
- (void) strlcpy(zc.zc_root, altroot, sizeof (zc.zc_root));
+ (void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value));
else
- zc.zc_root[0] = '\0';
+ zc.zc_value[0] = '\0';
verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
&zc.zc_guid) == 0);
- verify(nvlist_size(config, &len, NV_ENCODE_NATIVE) == 0);
-
- if ((packed = zfs_alloc(hdl, len)) == NULL)
+ if (zcmd_write_src_nvlist(hdl, &zc, config, NULL) != 0)
return (-1);
- verify(nvlist_pack(config, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);
-
- zc.zc_config_src = (uint64_t)(uintptr_t)packed;
- zc.zc_config_src_size = len;
-
ret = 0;
if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_IMPORT, &zc) != 0) {
char desc[1024];
@@ -722,7 +692,7 @@ zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
}
}
- free(packed);
+ zcmd_free_nvlists(&zc);
return (ret);
}
@@ -979,9 +949,7 @@ zpool_vdev_attach(zpool_handle_t *zhp,
{
zfs_cmd_t zc = { 0 };
char msg[1024];
- char *packed;
int ret;
- size_t len;
nvlist_t *tgt;
boolean_t avail_spare;
uint64_t val;
@@ -1045,19 +1013,12 @@ zpool_vdev_attach(zpool_handle_t *zhp,
return (zfs_error(hdl, EZFS_BADTARGET, msg));
}
- verify(nvlist_size(nvroot, &len, NV_ENCODE_NATIVE) == 0);
-
- if ((packed = zfs_alloc(zhp->zpool_hdl, len)) == NULL)
+ if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0)
return (-1);
- verify(nvlist_pack(nvroot, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);
-
- zc.zc_config_src = (uint64_t)(uintptr_t)packed;
- zc.zc_config_src_size = len;
-
ret = ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_ATTACH, &zc);
- free(packed);
+ zcmd_free_nvlists(&zc);
if (ret == 0)
return (0);
@@ -1224,7 +1185,7 @@ zpool_clear(zpool_handle_t *zhp, const char *path)
if (path)
(void) snprintf(msg, sizeof (msg),
dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
- zc.zc_prop_value);
+ path);
else
(void) snprintf(msg, sizeof (msg),
dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
@@ -1258,7 +1219,7 @@ do_zvol(zfs_handle_t *zhp, void *data)
* We check for volblocksize intead of ZFS_TYPE_VOLUME so that we
* correctly handle snapshots of volumes.
*/
- if (zhp->zfs_volblocksize != 0) {
+ if (ZFS_IS_VOLUME(zhp)) {
if (linktype)
ret = zvol_create_link(zhp->zfs_hdl, zhp->zfs_name);
else
@@ -1384,7 +1345,7 @@ set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path)
zfs_cmd_t zc = { 0 };
(void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
- (void) strncpy(zc.zc_prop_value, path, sizeof (zc.zc_prop_value));
+ (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value));
verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
&zc.zc_guid) == 0);
@@ -1494,7 +1455,8 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t ***list, size_t *nelem)
{
zfs_cmd_t zc = { 0 };
uint64_t count;
- zbookmark_t *zb;
+ zbookmark_t *zb = NULL;
+ libzfs_handle_t *hdl = zhp->zpool_hdl;
int i, j;
if (zhp->zpool_error_log != NULL) {
@@ -1510,19 +1472,19 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t ***list, size_t *nelem)
*/
verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT,
&count) == 0);
- if ((zc.zc_config_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl,
+ if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl,
count * sizeof (zbookmark_t))) == NULL)
return (-1);
- zc.zc_config_dst_size = count;
+ zc.zc_nvlist_dst_size = count;
(void) strcpy(zc.zc_name, zhp->zpool_name);
for (;;) {
if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG,
&zc) != 0) {
- free((void *)(uintptr_t)zc.zc_config_dst);
+ free((void *)(uintptr_t)zc.zc_nvlist_dst);
if (errno == ENOMEM) {
- if ((zc.zc_config_dst = (uintptr_t)
+ if ((zc.zc_nvlist_dst = (uintptr_t)
zfs_alloc(zhp->zpool_hdl,
- zc.zc_config_dst_size)) == NULL)
+ zc.zc_nvlist_dst_size)) == NULL)
return (-1);
} else {
return (-1);
@@ -1535,13 +1497,14 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t ***list, size_t *nelem)
/*
* Sort the resulting bookmarks. This is a little confusing due to the
* implementation of ZFS_IOC_ERROR_LOG. The bookmarks are copied last
- * to first, and 'zc_config_dst_size' indicates the number of boomarks
+ * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks
* _not_ copied as part of the process. So we point the start of our
* array appropriate and decrement the total number of elements.
*/
- zb = ((zbookmark_t *)(uintptr_t)zc.zc_config_dst) +
- zc.zc_config_dst_size;
- count -= zc.zc_config_dst_size;
+ zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) +
+ zc.zc_nvlist_dst_size;
+ count -= zc.zc_nvlist_dst_size;
+ zc.zc_nvlist_dst = 0ULL;
qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare);
@@ -1562,7 +1525,7 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t ***list, size_t *nelem)
*/
if (list == NULL) {
*nelem = j;
- free((void *)(uintptr_t)zc.zc_config_dst);
+ free((void *)(uintptr_t)zc.zc_nvlist_dst);
return (0);
}
@@ -1573,7 +1536,7 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t ***list, size_t *nelem)
*/
if ((zhp->zpool_error_log = zfs_alloc(zhp->zpool_hdl,
j * sizeof (nvlist_t *))) == NULL) {
- free((void *)(uintptr_t)zc.zc_config_dst);
+ free((void *)(uintptr_t)zc.zc_nvlist_dst);
return (-1);
}
@@ -1589,55 +1552,72 @@ zpool_get_errlog(zpool_handle_t *zhp, nvlist_t ***list, size_t *nelem)
sizeof (zbookmark_t)) == 0)
continue;
- if (nvlist_alloc(&nv, NV_UNIQUE_NAME,
- 0) != 0)
+ if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
goto nomem;
- zhp->zpool_error_log[j] = nv;
zc.zc_bookmark = zb[i];
- if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_BOOKMARK_NAME,
- &zc) == 0) {
- if (nvlist_add_string(nv, ZPOOL_ERR_DATASET,
- zc.zc_prop_name) != 0 ||
- nvlist_add_string(nv, ZPOOL_ERR_OBJECT,
- zc.zc_prop_value) != 0 ||
- nvlist_add_string(nv, ZPOOL_ERR_RANGE,
- zc.zc_filename) != 0)
- goto nomem;
- } else {
- (void) snprintf(buf, sizeof (buf), "%llx",
- zb[i].zb_objset);
- if (nvlist_add_string(nv,
- ZPOOL_ERR_DATASET, buf) != 0)
- goto nomem;
- (void) snprintf(buf, sizeof (buf), "%llx",
- zb[i].zb_object);
- if (nvlist_add_string(nv, ZPOOL_ERR_OBJECT,
- buf) != 0)
- goto nomem;
- (void) snprintf(buf, sizeof (buf), "lvl=%u blkid=%llu",
- (int)zb[i].zb_level, (long long)zb[i].zb_blkid);
- if (nvlist_add_string(nv, ZPOOL_ERR_RANGE,
- buf) != 0)
- goto nomem;
+ for (;;) {
+ if (ioctl(zhp->zpool_hdl->libzfs_fd,
+ ZFS_IOC_BOOKMARK_NAME, &zc) != 0) {
+ if (errno == ENOMEM) {
+ if (zcmd_expand_dst_nvlist(hdl, &zc)
+ != 0) {
+ zcmd_free_nvlists(&zc);
+ goto nomem;
+ }
+
+ continue;
+ } else {
+ if (nvlist_alloc(&nv, NV_UNIQUE_NAME,
+ 0) != 0)
+ goto nomem;
+
+ zhp->zpool_error_log[j] = nv;
+ (void) snprintf(buf, sizeof (buf),
+ "%llx", zb[i].zb_objset);
+ if (nvlist_add_string(nv,
+ ZPOOL_ERR_DATASET, buf) != 0)
+ goto nomem;
+ (void) snprintf(buf, sizeof (buf),
+ "%llx", zb[i].zb_object);
+ if (nvlist_add_string(nv,
+ ZPOOL_ERR_OBJECT, buf) != 0)
+ goto nomem;
+ (void) snprintf(buf, sizeof (buf),
+ "lvl=%u blkid=%llu",
+ (int)zb[i].zb_level,
+ (long long)zb[i].zb_blkid);
+ if (nvlist_add_string(nv,
+ ZPOOL_ERR_RANGE, buf) != 0)
+ goto nomem;
+ }
+ } else {
+ if (zcmd_read_dst_nvlist(hdl, &zc,
+ &zhp->zpool_error_log[j]) != 0) {
+ zcmd_free_nvlists(&zc);
+ goto nomem;
+ }
+ }
+
+ break;
}
+ zcmd_free_nvlists(&zc);
+
j++;
}
*list = zhp->zpool_error_log;
*nelem = zhp->zpool_error_count;
-
- free((void *)(uintptr_t)zc.zc_config_dst);
+ free(zb);
return (0);
nomem:
- free((void *)(uintptr_t)zc.zc_config_dst);
- for (i = 0; i < zhp->zpool_error_count; i++) {
- if (zhp->zpool_error_log[i])
- free(zhp->zpool_error_log[i]);
- }
+ free(zb);
+ free((void *)(uintptr_t)zc.zc_nvlist_dst);
+ for (i = 0; i < zhp->zpool_error_count; i++)
+ nvlist_free(zhp->zpool_error_log[i]);
free(zhp->zpool_error_log);
zhp->zpool_error_log = NULL;
return (no_memory(zhp->zpool_hdl));
diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c
index f2369efb5d..39fe569959 100644
--- a/usr/src/lib/libzfs/common/libzfs_util.c
+++ b/usr/src/lib/libzfs/common/libzfs_util.c
@@ -363,6 +363,24 @@ zfs_alloc(libzfs_handle_t *hdl, size_t size)
}
/*
+ * A safe form of realloc(), which also zeroes newly allocated space.
+ */
+void *
+zfs_realloc(libzfs_handle_t *hdl, void *ptr, size_t oldsize, size_t newsize)
+{
+ void *ret;
+
+ if ((ret = realloc(ptr, newsize)) == NULL) {
+ (void) no_memory(hdl);
+ free(ptr);
+ return (NULL);
+ }
+
+ bzero((char *)ret + oldsize, (newsize - oldsize));
+ return (ret);
+}
+
+/*
* A safe form of strdup() which will die if the allocation fails.
*/
char *
@@ -475,3 +493,85 @@ zfs_get_handle(zfs_handle_t *zhp)
{
return (zhp->zfs_hdl);
}
+
+/*
+ * Initialize the zc_nvlist_dst member to prepare for receiving an nvlist from
+ * an ioctl().
+ */
+int
+zcmd_alloc_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, size_t len)
+{
+ if (len == 0)
+ len = 1024;
+ zc->zc_nvlist_dst_size = len;
+ if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t)
+ zfs_alloc(hdl, zc->zc_nvlist_dst_size)) == NULL)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Called when an ioctl() which returns an nvlist fails with ENOMEM. This will
+ * expand the nvlist to the size specified in 'zc_nvlist_dst_size', which was
+ * filled in by the kernel to indicate the actual required size.
+ */
+int
+zcmd_expand_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc)
+{
+ free((void *)(uintptr_t)zc->zc_nvlist_dst);
+ if ((zc->zc_nvlist_dst = (uint64_t)(uintptr_t)
+ zfs_alloc(hdl, zc->zc_nvlist_dst_size))
+ == NULL)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Called to free the destination nvlist stored in the command structure. This
+ * is only needed if the caller must abort abnormally. The various other
+ * zcmd_*() routines will free it on failure (or on success, for
+ * zcmd_read_nvlist).
+ */
+void
+zcmd_free_nvlists(zfs_cmd_t *zc)
+{
+ free((void *)(uintptr_t)zc->zc_nvlist_src);
+ free((void *)(uintptr_t)zc->zc_nvlist_dst);
+}
+
+int
+zcmd_write_src_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t *nvl,
+ size_t *size)
+{
+ char *packed;
+ size_t len;
+
+ verify(nvlist_size(nvl, &len, NV_ENCODE_NATIVE) == 0);
+
+ if ((packed = zfs_alloc(hdl, len)) == NULL)
+ return (-1);
+
+ verify(nvlist_pack(nvl, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);
+
+ zc->zc_nvlist_src = (uint64_t)(uintptr_t)packed;
+ zc->zc_nvlist_src_size = len;
+
+ if (size)
+ *size = len;
+ return (0);
+}
+
+/*
+ * Unpacks an nvlist from the ZFS ioctl command structure.
+ */
+int
+zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp)
+{
+ if (nvlist_unpack((void *)(uintptr_t)zc->zc_nvlist_dst,
+ zc->zc_nvlist_dst_size, nvlp, 0) != 0)
+ return (no_memory(hdl));
+
+ return (0);
+}
diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers
index 84ba2663c4..11474a8bee 100644
--- a/usr/src/lib/libzfs/common/mapfile-vers
+++ b/usr/src/lib/libzfs/common/mapfile-vers
@@ -38,8 +38,11 @@ SUNWprivate_1.1 {
zfs_create;
zfs_destroy;
zfs_destroy_snaps;
+ zfs_expand_proplist;
+ zfs_free_proplist;
zfs_get_handle;
zfs_get_name;
+ zfs_get_user_props;
zfs_get_proplist;
zfs_get_type;
zfs_is_mounted;
@@ -56,7 +59,7 @@ SUNWprivate_1.1 {
zfs_nicestrtonum;
zfs_open;
zfs_promote;
- zfs_prop_column_format;
+ zfs_prop_align_right;
zfs_prop_column_name;
zfs_prop_default_numeric;
zfs_prop_default_string;
@@ -69,9 +72,10 @@ SUNWprivate_1.1 {
zfs_prop_readonly;
zfs_prop_set;
zfs_prop_to_name;
- zfs_prop_validate;
+ zfs_prop_user;
zfs_prop_valid_for_type;
zfs_prop_values;
+ zfs_prop_width;
zfs_receive;
zfs_refresh_properties;
zfs_rename;
diff --git a/usr/src/uts/common/fs/zfs/dmu.c b/usr/src/uts/common/fs/zfs/dmu.c
index 8db58a884d..81536337ed 100644
--- a/usr/src/uts/common/fs/zfs/dmu.c
+++ b/usr/src/uts/common/fs/zfs/dmu.c
@@ -1796,17 +1796,16 @@ dmu_object_size_from_db(dmu_buf_t *db, uint32_t *blksize, u_longlong_t *nblk512)
* human-readable format.
*/
int
-spa_bookmark_name(spa_t *spa, zbookmark_t *zb, char *dsname, size_t dslen,
- char *objname, size_t objlen, char *range, size_t rangelen)
+spa_bookmark_name(spa_t *spa, zbookmark_t *zb, nvlist_t *nvl)
{
dsl_pool_t *dp;
dsl_dataset_t *ds = NULL;
objset_t *os = NULL;
dnode_t *dn = NULL;
int err, shift;
-
- if (dslen < MAXNAMELEN || objlen < 32 || rangelen < 64)
- return (ENOSPC);
+ char dsname[MAXNAMELEN];
+ char objname[32];
+ char range[64];
dp = spa_get_dsl(spa);
if (zb->zb_objset != 0) {
@@ -1832,9 +1831,9 @@ spa_bookmark_name(spa_t *spa, zbookmark_t *zb, char *dsname, size_t dslen,
if (zb->zb_object == DMU_META_DNODE_OBJECT) {
- (void) strncpy(objname, "mdn", objlen);
+ (void) strncpy(objname, "mdn", sizeof (objname));
} else {
- (void) snprintf(objname, objlen, "%lld",
+ (void) snprintf(objname, sizeof (objname), "%lld",
(longlong_t)zb->zb_object);
}
@@ -1844,10 +1843,15 @@ spa_bookmark_name(spa_t *spa, zbookmark_t *zb, char *dsname, size_t dslen,
shift = (dn->dn_datablkshift?dn->dn_datablkshift:SPA_MAXBLOCKSHIFT) +
zb->zb_level * (dn->dn_indblkshift - SPA_BLKPTRSHIFT);
- (void) snprintf(range, rangelen, "%llu-%llu",
+ (void) snprintf(range, sizeof (range), "%llu-%llu",
(u_longlong_t)(zb->zb_blkid << shift),
(u_longlong_t)((zb->zb_blkid+1) << shift));
+ if ((err = nvlist_add_string(nvl, ZPOOL_ERR_DATASET, dsname)) != 0 ||
+ (err = nvlist_add_string(nvl, ZPOOL_ERR_OBJECT, objname)) != 0 ||
+ (err = nvlist_add_string(nvl, ZPOOL_ERR_RANGE, range)) != 0)
+ goto out;
+
out:
if (dn)
dnode_rele(dn, FTAG);
diff --git a/usr/src/uts/common/fs/zfs/dsl_prop.c b/usr/src/uts/common/fs/zfs/dsl_prop.c
index 0ad81ed920..5c615dad92 100644
--- a/usr/src/uts/common/fs/zfs/dsl_prop.c
+++ b/usr/src/uts/common/fs/zfs/dsl_prop.c
@@ -67,10 +67,13 @@ dsl_prop_get_impl(dsl_dir_t *dd, const char *propname,
int intsz, int numint, void *buf, char *setpoint)
{
int err = ENOENT;
+ zfs_prop_t prop;
if (setpoint)
setpoint[0] = '\0';
+ prop = zfs_name_to_prop(propname);
+
/*
* Note: dd may be NULL, therefore we shouldn't dereference it
* ouside this loop.
@@ -85,6 +88,13 @@ dsl_prop_get_impl(dsl_dir_t *dd, const char *propname,
dsl_dir_name(dd, setpoint);
break;
}
+
+ /*
+ * Break out of this loop for non-inheritable properties.
+ */
+ if (prop != ZFS_PROP_INVAL &&
+ !zfs_prop_inheritable(prop))
+ break;
}
if (err == ENOENT)
err = dodefault(propname, intsz, numint, buf);
@@ -403,7 +413,8 @@ dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
zap_attribute_t za;
char setpoint[MAXNAMELEN];
char *tmp;
- nvlist_t *prop;
+ nvlist_t *propval;
+ zfs_prop_t prop;
if (dsl_dataset_is_snapshot(ds)) {
VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
@@ -422,10 +433,19 @@ dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
for (zap_cursor_init(&zc, mos, dd->dd_phys->dd_props_zapobj);
(err = zap_cursor_retrieve(&zc, &za)) == 0;
zap_cursor_advance(&zc)) {
- if (nvlist_lookup_nvlist(*nvp, za.za_name, &prop) == 0)
+ /*
+ * Skip non-inheritable properties.
+ */
+ if ((prop = zfs_name_to_prop(za.za_name)) !=
+ ZFS_PROP_INVAL && !zfs_prop_inheritable(prop) &&
+ dd != ds->ds_dir)
+ continue;
+
+ if (nvlist_lookup_nvlist(*nvp, za.za_name,
+ &propval) == 0)
continue;
- VERIFY(nvlist_alloc(&prop, NV_UNIQUE_NAME,
+ VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME,
KM_SLEEP) == 0);
if (za.za_integer_length == 1) {
/*
@@ -440,7 +460,7 @@ dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
kmem_free(tmp, za.za_num_integers);
break;
}
- VERIFY(nvlist_add_string(prop,
+ VERIFY(nvlist_add_string(propval,
ZFS_PROP_VALUE, tmp) == 0);
kmem_free(tmp, za.za_num_integers);
} else {
@@ -448,15 +468,15 @@ dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
* Integer property
*/
ASSERT(za.za_integer_length == 8);
- (void) nvlist_add_uint64(prop, ZFS_PROP_VALUE,
- za.za_first_integer);
+ (void) nvlist_add_uint64(propval,
+ ZFS_PROP_VALUE, za.za_first_integer);
}
- VERIFY(nvlist_add_string(prop,
+ VERIFY(nvlist_add_string(propval,
ZFS_PROP_SOURCE, setpoint) == 0);
VERIFY(nvlist_add_nvlist(*nvp, za.za_name,
- prop) == 0);
- nvlist_free(prop);
+ propval) == 0);
+ nvlist_free(propval);
}
zap_cursor_fini(&zc);
diff --git a/usr/src/uts/common/fs/zfs/sys/spa.h b/usr/src/uts/common/fs/zfs/sys/spa.h
index 829c025af2..4f2eb50d1f 100644
--- a/usr/src/uts/common/fs/zfs/sys/spa.h
+++ b/usr/src/uts/common/fs/zfs/sys/spa.h
@@ -439,8 +439,8 @@ extern int spa_get_errlog(spa_t *spa, void *uaddr, size_t *count);
extern void spa_errlog_rotate(spa_t *spa);
extern void spa_errlog_drain(spa_t *spa);
extern void spa_errlog_sync(spa_t *spa, uint64_t txg);
-extern int spa_bookmark_name(spa_t *spa, struct zbookmark *zb, char *ds,
- size_t dsname, char *obj, size_t objname, char *range, size_t rangelen);
+extern int spa_bookmark_name(spa_t *spa, struct zbookmark *zb,
+ nvlist_t *nvl);
extern void spa_get_errlists(spa_t *spa, avl_tree_t *last, avl_tree_t *scrub);
/* Initialization and termination */
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_acl.h b/usr/src/uts/common/fs/zfs/sys/zfs_acl.h
index 34057e83c9..e3a653c5fa 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_acl.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_acl.h
@@ -77,11 +77,11 @@ typedef struct zfs_acl {
* whereas acl_inherit has secure instead of groupmask.
*/
-#define DISCARD 0
-#define NOALLOW 1
-#define GROUPMASK 2
-#define PASSTHROUGH 3
-#define SECURE 4
+#define ZFS_ACL_DISCARD 0
+#define ZFS_ACL_NOALLOW 1
+#define ZFS_ACL_GROUPMASK 2
+#define ZFS_ACL_PASSTHROUGH 3
+#define ZFS_ACL_SECURE 4
struct znode;
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h b/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
index a8f1f4ed89..b4f834e186 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
@@ -31,6 +31,7 @@
#include <sys/cred.h>
#include <sys/dmu.h>
#include <sys/zio.h>
+#include <sys/zvol.h>
#ifdef __cplusplus
extern "C" {
@@ -115,29 +116,29 @@ typedef struct zinject_record {
typedef struct zfs_cmd {
char zc_name[MAXPATHLEN];
- char zc_prop_name[MAXNAMELEN];
- char zc_prop_value[MAXPATHLEN];
- char zc_root[MAXPATHLEN];
- char zc_filename[MAXNAMELEN];
- uint32_t zc_intsz;
- uint32_t zc_numints;
+ char zc_value[MAXPATHLEN];
uint64_t zc_guid;
- uint64_t zc_config_src; /* really (char *) */
- uint64_t zc_config_src_size;
- uint64_t zc_config_dst; /* really (char *) */
- uint64_t zc_config_dst_size;
+ uint64_t zc_nvlist_src; /* really (char *) */
+ uint64_t zc_nvlist_src_size;
+ uint64_t zc_nvlist_dst; /* really (char *) */
+ uint64_t zc_nvlist_dst_size;
uint64_t zc_cookie;
uint64_t zc_cred;
uint64_t zc_dev;
- uint64_t zc_volsize;
- uint64_t zc_volblocksize;
uint64_t zc_objset_type;
dmu_objset_stats_t zc_objset_stats;
+ zvol_stats_t zc_vol_stats;
struct drr_begin zc_begin_record;
zinject_record_t zc_inject_record;
zbookmark_t zc_bookmark;
} zfs_cmd_t;
+typedef struct zfs_create_data {
+ cred_t *zc_cred;
+ dev_t zc_dev;
+ nvlist_t *zc_props;
+} zfs_create_data_t;
+
#define ZVOL_MAX_MINOR (1 << 16)
#define ZFS_MIN_MINOR (ZVOL_MAX_MINOR + 1)
@@ -145,30 +146,9 @@ typedef struct zfs_cmd {
extern dev_info_t *zfs_dip;
-extern int zfs_secpolicy_write(const char *dataset, const char *, cred_t *cr);
+extern int zfs_secpolicy_write(const char *dataset, cred_t *cr);
extern int zfs_busy(void);
-extern int zvol_check_volsize(zfs_cmd_t *zc, uint64_t blocksize);
-extern int zvol_check_volblocksize(zfs_cmd_t *zc);
-extern int zvol_get_stats(zfs_cmd_t *zc, objset_t *os);
-extern void zvol_create_cb(objset_t *os, void *arg, dmu_tx_t *tx);
-extern int zvol_create_minor(zfs_cmd_t *zc);
-extern int zvol_remove_minor(zfs_cmd_t *zc);
-extern int zvol_set_volsize(zfs_cmd_t *zc);
-extern int zvol_set_volblocksize(zfs_cmd_t *zc);
-extern int zvol_open(dev_t *devp, int flag, int otyp, cred_t *cr);
-extern int zvol_close(dev_t dev, int flag, int otyp, cred_t *cr);
-extern int zvol_strategy(buf_t *bp);
-extern int zvol_read(dev_t dev, uio_t *uiop, cred_t *cr);
-extern int zvol_write(dev_t dev, uio_t *uiop, cred_t *cr);
-extern int zvol_aread(dev_t dev, struct aio_req *aio, cred_t *cr);
-extern int zvol_awrite(dev_t dev, struct aio_req *aio, cred_t *cr);
-extern int zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr,
- int *rvalp);
-extern int zvol_busy(void);
-extern void zvol_init(void);
-extern void zvol_fini(void);
-
#endif /* _KERNEL */
#ifdef __cplusplus
diff --git a/usr/src/uts/common/fs/zfs/sys/zvol.h b/usr/src/uts/common/fs/zfs/sys/zvol.h
new file mode 100644
index 0000000000..9ddbfc2e21
--- /dev/null
+++ b/usr/src/uts/common/fs/zfs/sys/zvol.h
@@ -0,0 +1,71 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_ZVOL_H
+#define _SYS_ZVOL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct zvol_stats {
+ uint64_t zv_volsize;
+ uint64_t zv_volblocksize;
+} zvol_stats_t;
+
+#ifdef _KERNEL
+extern int zvol_check_volsize(uint64_t volsize, uint64_t blocksize);
+extern int zvol_check_volblocksize(uint64_t volblocksize);
+extern int zvol_get_stats(objset_t *os, zvol_stats_t *zvs);
+extern void zvol_create_cb(objset_t *os, void *arg, dmu_tx_t *tx);
+extern int zvol_create_minor(const char *, dev_t);
+extern int zvol_remove_minor(const char *);
+extern int zvol_set_volsize(const char *, dev_t, uint64_t);
+extern int zvol_set_volblocksize(const char *, uint64_t);
+
+extern int zvol_open(dev_t *devp, int flag, int otyp, cred_t *cr);
+extern int zvol_close(dev_t dev, int flag, int otyp, cred_t *cr);
+extern int zvol_strategy(buf_t *bp);
+extern int zvol_read(dev_t dev, uio_t *uiop, cred_t *cr);
+extern int zvol_write(dev_t dev, uio_t *uiop, cred_t *cr);
+extern int zvol_aread(dev_t dev, struct aio_req *aio, cred_t *cr);
+extern int zvol_awrite(dev_t dev, struct aio_req *aio, cred_t *cr);
+extern int zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr,
+ int *rvalp);
+extern int zvol_busy(void);
+extern void zvol_init(void);
+extern void zvol_fini(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ZVOL_H */
diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c
index 310ff9c917..430625b84f 100644
--- a/usr/src/uts/common/fs/zfs/zfs_acl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_acl.c
@@ -788,7 +788,7 @@ zfs_acl_chmod(znode_t *zp, uint64_t mode, zfs_acl_t *aclp,
}
- if (zfsvfs->z_acl_mode == DISCARD) {
+ if (zfsvfs->z_acl_mode == ZFS_ACL_DISCARD) {
zfs_ace_remove(aclp, i);
continue;
}
@@ -820,7 +820,7 @@ zfs_acl_chmod(znode_t *zp, uint64_t mode, zfs_acl_t *aclp,
* This is only applicable when the acl_mode
* property == groupmask.
*/
- if (zfsvfs->z_acl_mode == GROUPMASK) {
+ if (zfsvfs->z_acl_mode == ZFS_ACL_GROUPMASK) {
reuse_deny = zfs_reuse_deny(acep, i);
@@ -902,7 +902,7 @@ zfs_acl_chmod_setattr(znode_t *zp, uint64_t mode, dmu_tx_t *tx)
static void
zfs_securemode_update(zfsvfs_t *zfsvfs, ace_t *acep)
{
- if ((zfsvfs->z_acl_inherit == SECURE) &&
+ if ((zfsvfs->z_acl_inherit == ZFS_ACL_SECURE) &&
(acep->a_type == ALLOW))
acep->a_access_mask &= ~SECURE_CLEAR;
}
@@ -924,10 +924,10 @@ zfs_acl_inherit(znode_t *zp, zfs_acl_t *paclp)
i = j = 0;
pace_cnt = paclp->z_acl_count;
pacep = paclp->z_acl;
- if (zfsvfs->z_acl_inherit != DISCARD) {
+ if (zfsvfs->z_acl_inherit != ZFS_ACL_DISCARD) {
for (i = 0; i != pace_cnt; i++) {
- if (zfsvfs->z_acl_inherit == NOALLOW &&
+ if (zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW &&
pacep[i].a_type == ALLOW)
continue;
@@ -941,12 +941,12 @@ zfs_acl_inherit(znode_t *zp, zfs_acl_t *paclp)
}
aclp = zfs_acl_alloc(ace_cnt + OGE_PAD);
- if (ace_cnt && zfsvfs->z_acl_inherit != DISCARD) {
+ if (ace_cnt && zfsvfs->z_acl_inherit != ZFS_ACL_DISCARD) {
acep = aclp->z_acl;
pacep = paclp->z_acl;
for (i = 0; i != pace_cnt; i++) {
- if (zfsvfs->z_acl_inherit == NOALLOW &&
+ if (zfsvfs->z_acl_inherit == ZFS_ACL_NOALLOW &&
pacep[i].a_type == ALLOW)
continue;
diff --git a/usr/src/uts/common/fs/zfs/zfs_ctldir.c b/usr/src/uts/common/fs/zfs/zfs_ctldir.c
index e890530701..cb0807aa56 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ctldir.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ctldir.c
@@ -513,7 +513,7 @@ zfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
err = zfsctl_snapshot_zname(sdvp, snm, MAXNAMELEN, from);
if (err)
return (err);
- err = zfs_secpolicy_write(from, NULL, cr);
+ err = zfs_secpolicy_write(from, cr);
if (err)
return (err);
@@ -558,7 +558,7 @@ zfsctl_snapdir_remove(vnode_t *dvp, char *name, vnode_t *cwd, cred_t *cr)
err = zfsctl_snapshot_zname(dvp, name, MAXNAMELEN, snapname);
if (err)
return (err);
- err = zfs_secpolicy_write(snapname, NULL, cr);
+ err = zfs_secpolicy_write(snapname, cr);
if (err)
return (err);
diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
index 029138ff3a..e51c1587df 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
@@ -58,6 +58,7 @@
#include <sys/zfs_ctldir.h>
#include "zfs_namecheck.h"
+#include "zfs_prop.h"
extern struct modlfs zfs_modlfs;
@@ -68,7 +69,7 @@ ldi_ident_t zfs_li = NULL;
dev_info_t *zfs_dip;
typedef int zfs_ioc_func_t(zfs_cmd_t *);
-typedef int zfs_secpolicy_func_t(const char *, const char *, cred_t *);
+typedef int zfs_secpolicy_func_t(const char *, cred_t *);
typedef struct zfs_ioc_vec {
zfs_ioc_func_t *zvec_func;
@@ -122,7 +123,7 @@ __dprintf(const char *file, const char *func, int line, const char *fmt, ...)
*/
/* ARGSUSED */
static int
-zfs_secpolicy_none(const char *unused1, const char *unused2, cred_t *cr)
+zfs_secpolicy_none(const char *unused1, cred_t *cr)
{
return (0);
}
@@ -133,7 +134,7 @@ zfs_secpolicy_none(const char *unused1, const char *unused2, cred_t *cr)
*/
/* ARGSUSED */
static int
-zfs_secpolicy_read(const char *dataset, const char *unused, cred_t *cr)
+zfs_secpolicy_read(const char *dataset, cred_t *cr)
{
if (INGLOBALZONE(curproc) ||
zone_dataset_visible(dataset, NULL))
@@ -184,9 +185,8 @@ zfs_dozonecheck(const char *dataset, cred_t *cr)
* Policy for dataset write operations (create children, set properties, etc).
* Requires SYS_MOUNT privilege, and must be writable in the local zone.
*/
-/* ARGSUSED */
int
-zfs_secpolicy_write(const char *dataset, const char *unused, cred_t *cr)
+zfs_secpolicy_write(const char *dataset, cred_t *cr)
{
int error;
@@ -201,7 +201,7 @@ zfs_secpolicy_write(const char *dataset, const char *unused, cred_t *cr)
* create, destroy, snapshot, clone, restore.
*/
static int
-zfs_secpolicy_parent(const char *dataset, const char *unused, cred_t *cr)
+zfs_secpolicy_parent(const char *dataset, cred_t *cr)
{
char parentname[MAXNAMELEN];
char *cp;
@@ -221,65 +221,7 @@ zfs_secpolicy_parent(const char *dataset, const char *unused, cred_t *cr)
}
- return (zfs_secpolicy_write(parentname, unused, cr));
-}
-
-/*
- * Policy for dataset write operations (create children, set properties, etc).
- * Requires SYS_MOUNT privilege, and must be writable in the local zone.
- */
-static int
-zfs_secpolicy_setprop(const char *dataset, const char *prop, cred_t *cr)
-{
- int error;
-
- if (error = zfs_dozonecheck(dataset, cr))
- return (error);
-
- if (strcmp(prop, "zoned") == 0) {
- /*
- * Disallow setting of 'zoned' from within a local zone.
- */
- if (!INGLOBALZONE(curproc))
- return (EPERM);
- }
-
- return (secpolicy_zfs(cr));
-}
-
-/*
- * Security policy for setting the quota. This is the same as
- * zfs_secpolicy_write, except that the local zone may not change the quota at
- * the zone-property setpoint.
- */
-/* ARGSUSED */
-static int
-zfs_secpolicy_quota(const char *dataset, const char *unused, cred_t *cr)
-{
- int error;
-
- if (error = zfs_dozonecheck(dataset, cr))
- return (error);
-
- if (!INGLOBALZONE(curproc)) {
- uint64_t zoned;
- char setpoint[MAXNAMELEN];
- int dslen;
- /*
- * Unprivileged users are allowed to modify the quota
- * on things *under* (ie. contained by) the thing they
- * own.
- */
- if (dsl_prop_get_integer(dataset, "zoned", &zoned, setpoint))
- return (EPERM);
- if (!zoned) /* this shouldn't happen */
- return (EPERM);
- dslen = strlen(dataset);
- if (dslen <= strlen(setpoint))
- return (EPERM);
- }
-
- return (secpolicy_zfs(cr));
+ return (zfs_secpolicy_write(parentname, cr));
}
/*
@@ -288,7 +230,7 @@ zfs_secpolicy_quota(const char *dataset, const char *unused, cred_t *cr)
*/
/* ARGSUSED */
static int
-zfs_secpolicy_config(const char *unused, const char *unused2, cred_t *cr)
+zfs_secpolicy_config(const char *unused, cred_t *cr)
{
if (secpolicy_sys_config(cr, B_FALSE) != 0)
return (EPERM);
@@ -301,7 +243,7 @@ zfs_secpolicy_config(const char *unused, const char *unused2, cred_t *cr)
*/
/* ARGSUSED */
static int
-zfs_secpolicy_inject(const char *unused, const char *unused2, cred_t *cr)
+zfs_secpolicy_inject(const char *unused, cred_t *cr)
{
return (secpolicy_zinject(cr));
}
@@ -310,7 +252,7 @@ zfs_secpolicy_inject(const char *unused, const char *unused2, cred_t *cr)
* Returns the nvlist as specified by the user in the zfs_cmd_t.
*/
static int
-get_config(zfs_cmd_t *zc, nvlist_t **nvp)
+get_nvlist(zfs_cmd_t *zc, nvlist_t **nvp)
{
char *packed;
size_t size;
@@ -318,16 +260,14 @@ get_config(zfs_cmd_t *zc, nvlist_t **nvp)
nvlist_t *config = NULL;
/*
- * Read in and unpack the user-supplied nvlist. By this point, we know
- * that the user has the SYS_CONFIG privilege, so allocating arbitrary
- * sized regions of memory should not be a problem.
+ * Read in and unpack the user-supplied nvlist.
*/
- if ((size = zc->zc_config_src_size) == 0)
+ if ((size = zc->zc_nvlist_src_size) == 0)
return (EINVAL);
packed = kmem_alloc(size, KM_SLEEP);
- if ((error = xcopyin((void *)(uintptr_t)zc->zc_config_src, packed,
+ if ((error = xcopyin((void *)(uintptr_t)zc->zc_nvlist_src, packed,
size)) != 0) {
kmem_free(packed, size);
return (error);
@@ -345,16 +285,39 @@ get_config(zfs_cmd_t *zc, nvlist_t **nvp)
}
static int
+put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
+{
+ char *packed = NULL;
+ size_t size;
+ int error;
+
+ VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
+
+ if (size > zc->zc_nvlist_dst_size) {
+ error = ENOMEM;
+ } else {
+ VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
+ KM_SLEEP) == 0);
+ error = xcopyout(packed, (void *)(uintptr_t)zc->zc_nvlist_dst,
+ size);
+ kmem_free(packed, size);
+ }
+
+ zc->zc_nvlist_dst_size = size;
+ return (error);
+}
+
+static int
zfs_ioc_pool_create(zfs_cmd_t *zc)
{
int error;
nvlist_t *config;
- if ((error = get_config(zc, &config)) != 0)
+ if ((error = get_nvlist(zc, &config)) != 0)
return (error);
- error = spa_create(zc->zc_name, config, zc->zc_root[0] == '\0' ?
- NULL : zc->zc_root);
+ error = spa_create(zc->zc_name, config, zc->zc_value[0] == '\0' ?
+ NULL : zc->zc_value);
nvlist_free(config);
@@ -374,7 +337,7 @@ zfs_ioc_pool_import(zfs_cmd_t *zc)
nvlist_t *config;
uint64_t guid;
- if ((error = get_config(zc, &config)) != 0)
+ if ((error = get_nvlist(zc, &config)) != 0)
return (error);
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) != 0 ||
@@ -382,7 +345,7 @@ zfs_ioc_pool_import(zfs_cmd_t *zc)
error = EINVAL;
else
error = spa_import(zc->zc_name, config,
- zc->zc_root[0] == '\0' ? NULL : zc->zc_root);
+ zc->zc_value[0] == '\0' ? NULL : zc->zc_value);
nvlist_free(config);
@@ -399,25 +362,13 @@ static int
zfs_ioc_pool_configs(zfs_cmd_t *zc)
{
nvlist_t *configs;
- char *packed = NULL;
- size_t size = 0;
int error;
if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL)
return (EEXIST);
- VERIFY(nvlist_pack(configs, &packed, &size, NV_ENCODE_NATIVE,
- KM_SLEEP) == 0);
+ error = put_nvlist(zc, configs);
- if (size > zc->zc_config_dst_size)
- error = ENOMEM;
- else
- error = xcopyout(packed, (void *)(uintptr_t)zc->zc_config_dst,
- size);
-
- zc->zc_config_dst_size = size;
-
- kmem_free(packed, size);
nvlist_free(configs);
return (error);
@@ -427,27 +378,14 @@ static int
zfs_ioc_pool_stats(zfs_cmd_t *zc)
{
nvlist_t *config;
- char *packed = NULL;
- size_t size = 0;
int error;
int ret = 0;
- error = spa_get_stats(zc->zc_name, &config, zc->zc_root,
- sizeof (zc->zc_root));
+ error = spa_get_stats(zc->zc_name, &config, zc->zc_value,
+ sizeof (zc->zc_value));
if (config != NULL) {
- VERIFY(nvlist_pack(config, &packed, &size,
- NV_ENCODE_NATIVE, KM_SLEEP) == 0);
-
- if (size > zc->zc_config_dst_size)
- ret = ENOMEM;
- else if (xcopyout(packed, (void *)(uintptr_t)zc->zc_config_dst,
- size))
- ret = EFAULT;
-
- zc->zc_config_dst_size = size;
-
- kmem_free(packed, size);
+ ret = put_nvlist(zc, config);
nvlist_free(config);
/*
@@ -471,11 +409,9 @@ static int
zfs_ioc_pool_tryimport(zfs_cmd_t *zc)
{
nvlist_t *tryconfig, *config;
- char *packed = NULL;
- size_t size = 0;
int error;
- if ((error = get_config(zc, &tryconfig)) != 0)
+ if ((error = get_nvlist(zc, &tryconfig)) != 0)
return (error);
config = spa_tryimport(tryconfig);
@@ -485,18 +421,7 @@ zfs_ioc_pool_tryimport(zfs_cmd_t *zc)
if (config == NULL)
return (EINVAL);
- VERIFY(nvlist_pack(config, &packed, &size, NV_ENCODE_NATIVE,
- KM_SLEEP) == 0);
-
- if (size > zc->zc_config_dst_size)
- error = ENOMEM;
- else
- error = xcopyout(packed, (void *)(uintptr_t)zc->zc_config_dst,
- size);
-
- zc->zc_config_dst_size = size;
-
- kmem_free(packed, size);
+ error = put_nvlist(zc, config);
nvlist_free(config);
return (error);
@@ -555,7 +480,7 @@ zfs_ioc_vdev_add(zfs_cmd_t *zc)
if (error != 0)
return (error);
- if ((error = get_config(zc, &config)) == 0) {
+ if ((error = get_nvlist(zc, &config)) == 0) {
error = spa_vdev_add(spa, config);
nvlist_free(config);
}
@@ -619,7 +544,7 @@ zfs_ioc_vdev_attach(zfs_cmd_t *zc)
if (error != 0)
return (error);
- if ((error = get_config(zc, &config)) == 0) {
+ if ((error = get_nvlist(zc, &config)) == 0) {
error = spa_vdev_attach(spa, zc->zc_guid, config, replacing);
nvlist_free(config);
}
@@ -648,7 +573,7 @@ static int
zfs_ioc_vdev_setpath(zfs_cmd_t *zc)
{
spa_t *spa;
- char *path = zc->zc_prop_value;
+ char *path = zc->zc_value;
uint64_t guid = zc->zc_guid;
int error;
@@ -668,8 +593,6 @@ zfs_ioc_objset_stats(zfs_cmd_t *zc)
objset_t *os = NULL;
int error;
nvlist_t *nv;
- size_t sz;
- char *buf;
retry:
error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
@@ -691,27 +614,16 @@ retry:
dmu_objset_stats(os, &zc->zc_objset_stats);
- if (zc->zc_config_src != NULL &&
+ if (zc->zc_nvlist_dst != NULL &&
(error = dsl_prop_get_all(os, &nv)) == 0) {
- VERIFY(nvlist_size(nv, &sz, NV_ENCODE_NATIVE) == 0);
- if (sz > zc->zc_config_src_size) {
- zc->zc_config_src_size = sz;
- error = ENOMEM;
- } else {
- buf = kmem_alloc(sz, KM_SLEEP);
- VERIFY(nvlist_pack(nv, &buf, &sz,
- NV_ENCODE_NATIVE, 0) == 0);
- error = xcopyout(buf,
- (void *)(uintptr_t)zc->zc_config_src, sz);
- kmem_free(buf, sz);
- }
+ error = put_nvlist(zc, nv);
nvlist_free(nv);
}
if (!error && zc->zc_objset_stats.dds_type == DMU_OST_ZVOL)
- error = zvol_get_stats(zc, os);
+ error = zvol_get_stats(os, &zc->zc_vol_stats);
- spa_altroot(dmu_objset_spa(os), zc->zc_root, sizeof (zc->zc_root));
+ spa_altroot(dmu_objset_spa(os), zc->zc_value, sizeof (zc->zc_value));
dmu_objset_close(os);
return (error);
@@ -818,46 +730,215 @@ retry:
}
static int
-zfs_ioc_set_prop(zfs_cmd_t *zc)
+zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl)
{
- return (dsl_prop_set(zc->zc_name, zc->zc_prop_name,
- zc->zc_intsz, zc->zc_numints, zc->zc_prop_value));
-}
+ nvpair_t *elem;
+ int error;
+ const char *propname;
+ zfs_prop_t prop;
+ uint64_t intval;
+ char *strval;
+
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
+ propname = nvpair_name(elem);
+
+ if ((prop = zfs_name_to_prop(propname)) ==
+ ZFS_PROP_INVAL) {
+ /*
+ * If this is a user-defined property, it must be a
+ * string, and there is no further validation to do.
+ */
+ if (!zfs_prop_user(propname) ||
+ nvpair_type(elem) != DATA_TYPE_STRING)
+ return (EINVAL);
+
+ VERIFY(nvpair_value_string(elem, &strval) == 0);
+ error = dsl_prop_set(name, propname, 1,
+ strlen(strval) + 1, strval);
+ if (error == 0)
+ continue;
+ else
+ break;
+ }
-static int
-zfs_ioc_set_quota(zfs_cmd_t *zc)
-{
- return (dsl_dir_set_quota(zc->zc_name, zc->zc_cookie));
-}
+ /*
+ * Check permissions for special properties.
+ */
+ switch (prop) {
+ case ZFS_PROP_ZONED:
+ /*
+ * Disallow setting of 'zoned' from within a local zone.
+ */
+ if (!INGLOBALZONE(curproc))
+ return (EPERM);
+ break;
-static int
-zfs_ioc_set_reservation(zfs_cmd_t *zc)
-{
- return (dsl_dir_set_reservation(zc->zc_name, zc->zc_cookie));
-}
+ case ZFS_PROP_QUOTA:
+ if (error = zfs_dozonecheck(name, cr))
+ return (error);
-static int
-zfs_ioc_set_volsize(zfs_cmd_t *zc)
-{
- return (zvol_set_volsize(zc));
+ if (!INGLOBALZONE(curproc)) {
+ uint64_t zoned;
+ char setpoint[MAXNAMELEN];
+ int dslen;
+ /*
+ * Unprivileged users are allowed to modify the
+ * quota on things *under* (ie. contained by)
+ * the thing they own.
+ */
+ if (dsl_prop_get_integer(name, "zoned", &zoned,
+ setpoint))
+ return (EPERM);
+ if (!zoned) /* this shouldn't happen */
+ return (EPERM);
+ dslen = strlen(name);
+ if (dslen <= strlen(setpoint))
+ return (EPERM);
+ }
+ }
+
+ switch (prop) {
+ case ZFS_PROP_QUOTA:
+ if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
+ (error = dsl_dir_set_quota(name,
+ intval)) != 0)
+ return (error);
+ break;
+
+ case ZFS_PROP_RESERVATION:
+ if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
+ (error = dsl_dir_set_reservation(name,
+ intval)) != 0)
+ return (error);
+ break;
+
+ case ZFS_PROP_VOLSIZE:
+ if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
+ (error = zvol_set_volsize(name, dev,
+ intval)) != 0)
+ return (error);
+ break;
+
+ case ZFS_PROP_VOLBLOCKSIZE:
+ if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
+ (error = zvol_set_volblocksize(name,
+ intval)) != 0)
+ return (error);
+ break;
+
+ default:
+ if (nvpair_type(elem) == DATA_TYPE_STRING) {
+ if (zfs_prop_get_type(prop) !=
+ prop_type_string)
+ return (EINVAL);
+ ASSERT(nvpair_value_string(elem, &strval) == 0);
+ error = dsl_prop_set(name,
+ nvpair_name(elem), 1, strlen(strval) + 1,
+ strval);
+ } else if (nvpair_type(elem) == DATA_TYPE_UINT64) {
+ ASSERT(nvpair_value_uint64(elem, &intval) == 0);
+
+ switch (zfs_prop_get_type(prop)) {
+ case prop_type_number:
+ break;
+ case prop_type_boolean:
+ if (intval > 1)
+ error = EINVAL;
+ break;
+ case prop_type_string:
+ error = EINVAL;
+ break;
+ case prop_type_index:
+ switch (prop) {
+ case ZFS_PROP_CHECKSUM:
+ if (intval >=
+ ZIO_CHECKSUM_FUNCTIONS)
+ error = EINVAL;
+ break;
+ case ZFS_PROP_COMPRESSION:
+ if (intval >=
+ ZIO_COMPRESS_FUNCTIONS)
+ error = EINVAL;
+ break;
+ case ZFS_PROP_SNAPDIR:
+ if (intval >
+ ZFS_SNAPDIR_VISIBLE)
+ error = EINVAL;
+ break;
+ case ZFS_PROP_ACLMODE:
+ if (intval >
+ ZFS_ACL_PASSTHROUGH)
+ error = EINVAL;
+ break;
+ case ZFS_PROP_ACLINHERIT:
+ if (intval > ZFS_ACL_SECURE ||
+ intval == ZFS_ACL_GROUPMASK)
+ error = EINVAL;
+ break;
+ default:
+ cmn_err(CE_PANIC,
+ "unknown index property");
+ }
+ break;
+ default:
+ cmn_err(CE_PANIC, "unknown property "
+ "type");
+ break;
+ }
+
+ error = dsl_prop_set(name, propname, 8, 1,
+ &intval);
+ } else {
+ return (EINVAL);
+ }
+ break;
+ }
+ }
+
+ return (0);
}
static int
-zfs_ioc_set_volblocksize(zfs_cmd_t *zc)
+zfs_ioc_set_prop(zfs_cmd_t *zc)
{
- return (zvol_set_volblocksize(zc));
+ nvlist_t *nvl;
+ int error;
+ zfs_prop_t prop;
+
+ /*
+ * If zc_value is set, then this is an attempt to inherit a value.
+ * Otherwise, zc_nvlist refers to a list of properties to set.
+ */
+ if (zc->zc_value[0] != '\0') {
+ if (!zfs_prop_user(zc->zc_value) &&
+ ((prop = zfs_name_to_prop(zc->zc_value)) ==
+ ZFS_PROP_INVAL ||
+ !zfs_prop_inheritable(prop)))
+ return (EINVAL);
+
+ return (dsl_prop_set(zc->zc_name, zc->zc_value, 0, 0, NULL));
+ }
+
+ if ((error = get_nvlist(zc, &nvl)) != 0)
+ return (error);
+
+ error = zfs_set_prop_nvlist(zc->zc_name, zc->zc_dev,
+ (cred_t *)(uintptr_t)zc->zc_cred, nvl);
+ nvlist_free(nvl);
+ return (error);
}
static int
zfs_ioc_create_minor(zfs_cmd_t *zc)
{
- return (zvol_create_minor(zc));
+ return (zvol_create_minor(zc->zc_name, zc->zc_dev));
}
static int
zfs_ioc_remove_minor(zfs_cmd_t *zc)
{
- return (zvol_remove_minor(zc));
+ return (zvol_remove_minor(zc->zc_name));
}
/*
@@ -888,7 +969,7 @@ zfs_get_vfs(const char *resource)
static void
zfs_create_cb(objset_t *os, void *arg, dmu_tx_t *tx)
{
- zfs_cmd_t *zc = arg;
+ zfs_create_data_t *zc = arg;
zfs_create_fs(os, (cred_t *)(uintptr_t)zc->zc_cred, tx);
}
@@ -897,6 +978,7 @@ zfs_ioc_create(zfs_cmd_t *zc)
{
objset_t *clone;
int error = 0;
+ zfs_create_data_t cbdata = { 0 };
void (*cbfunc)(objset_t *os, void *arg, dmu_tx_t *tx);
dmu_objset_type_t type = zc->zc_objset_type;
@@ -916,47 +998,93 @@ zfs_ioc_create(zfs_cmd_t *zc)
if (strchr(zc->zc_name, '@'))
return (EINVAL);
- if (zc->zc_filename[0] != '\0') {
+ if (zc->zc_nvlist_src != NULL &&
+ (error = get_nvlist(zc, &cbdata.zc_props)) != 0)
+ return (error);
+
+ cbdata.zc_cred = (cred_t *)(uintptr_t)zc->zc_cred;
+ cbdata.zc_dev = (dev_t)zc->zc_dev;
+
+ if (zc->zc_value[0] != '\0') {
/*
* We're creating a clone of an existing snapshot.
*/
- zc->zc_filename[sizeof (zc->zc_filename) - 1] = '\0';
- if (dataset_namecheck(zc->zc_filename, NULL, NULL) != 0)
+ zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
+ if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0) {
+ nvlist_free(cbdata.zc_props);
return (EINVAL);
+ }
- error = dmu_objset_open(zc->zc_filename, type,
+ error = dmu_objset_open(zc->zc_value, type,
DS_MODE_STANDARD | DS_MODE_READONLY, &clone);
- if (error)
+ if (error) {
+ nvlist_free(cbdata.zc_props);
return (error);
+ }
error = dmu_objset_create(zc->zc_name, type, clone, NULL, NULL);
dmu_objset_close(clone);
} else {
- if (cbfunc == NULL)
+ if (cbfunc == NULL) {
+ nvlist_free(cbdata.zc_props);
return (EINVAL);
- /*
- * We're creating a new dataset.
- */
- if (type == DMU_OST_ZVOL) {
-
- if ((error = zvol_check_volblocksize(zc)) != 0)
- return (error);
+ }
- if ((error = zvol_check_volsize(zc,
- zc->zc_volblocksize)) != 0)
+ if (type == DMU_OST_ZVOL) {
+ uint64_t volsize, volblocksize;
+
+ if (cbdata.zc_props == NULL ||
+ nvlist_lookup_uint64(cbdata.zc_props,
+ zfs_prop_to_name(ZFS_PROP_VOLSIZE),
+ &volsize) != 0) {
+ nvlist_free(cbdata.zc_props);
+ return (EINVAL);
+ }
+
+ if ((error = nvlist_lookup_uint64(cbdata.zc_props,
+ zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+ &volblocksize)) != 0 && error != ENOENT) {
+ nvlist_free(cbdata.zc_props);
+ return (EINVAL);
+ }
+
+ if (error != 0)
+ volblocksize = zfs_prop_default_numeric(
+ ZFS_PROP_VOLBLOCKSIZE);
+
+ if ((error = zvol_check_volblocksize(
+ volblocksize)) != 0 ||
+ (error = zvol_check_volsize(volsize,
+ volblocksize)) != 0) {
+ nvlist_free(cbdata.zc_props);
return (error);
+ }
}
- error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc, zc);
+
+ error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc,
+ &cbdata);
}
+
+ /*
+ * It would be nice to do this atomically.
+ */
+ if (error == 0) {
+ if ((error = zfs_set_prop_nvlist(zc->zc_name,
+ zc->zc_dev, (cred_t *)(uintptr_t)zc->zc_cred,
+ cbdata.zc_props)) != 0)
+ (void) dmu_objset_destroy(zc->zc_name);
+ }
+
+ nvlist_free(cbdata.zc_props);
return (error);
}
static int
zfs_ioc_snapshot(zfs_cmd_t *zc)
{
- if (snapshot_namecheck(zc->zc_prop_value, NULL, NULL) != 0)
+ if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
return (EINVAL);
return (dmu_objset_snapshot(zc->zc_name,
- zc->zc_prop_value, zc->zc_cookie));
+ zc->zc_value, zc->zc_cookie));
}
static int
@@ -1004,13 +1132,13 @@ zfs_ioc_destroy_snaps(zfs_cmd_t *zc)
{
int err;
- if (snapshot_namecheck(zc->zc_prop_value, NULL, NULL) != 0)
+ if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0)
return (EINVAL);
err = dmu_objset_find(zc->zc_name,
- zfs_unmount_snap, zc->zc_prop_value, DS_FIND_CHILDREN);
+ zfs_unmount_snap, zc->zc_value, DS_FIND_CHILDREN);
if (err)
return (err);
- return (dmu_snapshots_destroy(zc->zc_name, zc->zc_prop_value));
+ return (dmu_snapshots_destroy(zc->zc_name, zc->zc_value));
}
static int
@@ -1034,8 +1162,8 @@ zfs_ioc_rollback(zfs_cmd_t *zc)
static int
zfs_ioc_rename(zfs_cmd_t *zc)
{
- zc->zc_prop_value[sizeof (zc->zc_prop_value) - 1] = '\0';
- if (dataset_namecheck(zc->zc_prop_value, NULL, NULL) != 0)
+ zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
+ if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0)
return (EINVAL);
if (strchr(zc->zc_name, '@') != NULL &&
@@ -1045,7 +1173,7 @@ zfs_ioc_rename(zfs_cmd_t *zc)
return (err);
}
- return (dmu_objset_rename(zc->zc_name, zc->zc_prop_value));
+ return (dmu_objset_rename(zc->zc_name, zc->zc_value));
}
static int
@@ -1058,8 +1186,8 @@ zfs_ioc_recvbackup(zfs_cmd_t *zc)
fp = getf(fd);
if (fp == NULL)
return (EBADF);
- error = dmu_recvbackup(zc->zc_filename, &zc->zc_begin_record,
- &zc->zc_cookie, (boolean_t)zc->zc_numints, fp->f_vnode,
+ error = dmu_recvbackup(zc->zc_value, &zc->zc_begin_record,
+ &zc->zc_cookie, (boolean_t)zc->zc_guid, fp->f_vnode,
fp->f_offset);
releasef(fd);
return (error);
@@ -1078,8 +1206,8 @@ zfs_ioc_sendbackup(zfs_cmd_t *zc)
if (error)
return (error);
- if (zc->zc_prop_value[0] != '\0') {
- error = dmu_objset_open(zc->zc_prop_value, DMU_OST_ANY,
+ if (zc->zc_value[0] != '\0') {
+ error = dmu_objset_open(zc->zc_value, DMU_OST_ANY,
DS_MODE_STANDARD | DS_MODE_READONLY, &fromsnap);
if (error) {
dmu_objset_close(tosnap);
@@ -1143,17 +1271,17 @@ zfs_ioc_error_log(zfs_cmd_t *zc)
{
spa_t *spa;
int error;
- size_t count = (size_t)zc->zc_config_dst_size;
+ size_t count = (size_t)zc->zc_nvlist_dst_size;
if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
return (error);
- error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_config_dst,
+ error = spa_get_errlog(spa, (void *)(uintptr_t)zc->zc_nvlist_dst,
&count);
if (error == 0)
- zc->zc_config_dst_size = count;
+ zc->zc_nvlist_dst_size = count;
else
- zc->zc_config_dst_size = spa_get_errlog_size(spa);
+ zc->zc_nvlist_dst_size = spa_get_errlog_size(spa);
spa_close(spa, FTAG);
@@ -1172,9 +1300,9 @@ zfs_ioc_clear(zfs_cmd_t *zc)
spa_config_enter(spa, RW_WRITER, FTAG);
- if (zc->zc_prop_value[0] == '\0')
+ if (zc->zc_guid == 0) {
vd = NULL;
- else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) {
+ } else if ((vd = spa_lookup_by_guid(spa, zc->zc_guid)) == NULL) {
spa_config_exit(spa, FTAG);
spa_close(spa, FTAG);
return (ENODEV);
@@ -1194,14 +1322,17 @@ zfs_ioc_bookmark_name(zfs_cmd_t *zc)
{
spa_t *spa;
int error;
+ nvlist_t *nvl;
if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0)
return (error);
- error = spa_bookmark_name(spa, &zc->zc_bookmark,
- zc->zc_prop_name, sizeof (zc->zc_prop_name), zc->zc_prop_value,
- sizeof (zc->zc_prop_value), zc->zc_filename,
- sizeof (zc->zc_filename));
+ VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+ error = spa_bookmark_name(spa, &zc->zc_bookmark, nvl);
+ if (error == 0)
+ error = put_nvlist(zc, nvl);
+ nvlist_free(nvl);
spa_close(spa, FTAG);
@@ -1217,10 +1348,10 @@ zfs_ioc_promote(zfs_cmd_t *zc)
* We don't need to unmount *all* the origin fs's snapshots, but
* it's easier.
*/
- cp = strchr(zc->zc_prop_value, '@');
+ cp = strchr(zc->zc_value, '@');
if (cp)
*cp = '\0';
- (void) dmu_objset_find(zc->zc_prop_value,
+ (void) dmu_objset_find(zc->zc_value,
zfs_unmount_snap, NULL, DS_FIND_SNAPSHOTS);
return (dsl_dataset_promote(zc->zc_name));
}
@@ -1246,11 +1377,7 @@ static zfs_ioc_vec_t zfs_ioc_vec[] = {
{ zfs_ioc_objset_stats, zfs_secpolicy_read, dataset_name },
{ zfs_ioc_dataset_list_next, zfs_secpolicy_read, dataset_name },
{ zfs_ioc_snapshot_list_next, zfs_secpolicy_read, dataset_name },
- { zfs_ioc_set_prop, zfs_secpolicy_setprop, dataset_name },
- { zfs_ioc_set_quota, zfs_secpolicy_quota, dataset_name },
- { zfs_ioc_set_reservation, zfs_secpolicy_write, dataset_name },
- { zfs_ioc_set_volsize, zfs_secpolicy_config, dataset_name },
- { zfs_ioc_set_volblocksize, zfs_secpolicy_config, dataset_name },
+ { zfs_ioc_set_prop, zfs_secpolicy_write, dataset_name },
{ zfs_ioc_create_minor, zfs_secpolicy_config, dataset_name },
{ zfs_ioc_remove_minor, zfs_secpolicy_config, dataset_name },
{ zfs_ioc_create, zfs_secpolicy_parent, dataset_name },
@@ -1292,8 +1419,7 @@ zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
if (error == 0) {
zc->zc_cred = (uintptr_t)cr;
zc->zc_dev = dev;
- error = zfs_ioc_vec[vec].zvec_secpolicy(zc->zc_name,
- zc->zc_prop_name, cr);
+ error = zfs_ioc_vec[vec].zvec_secpolicy(zc->zc_name, cr);
}
/*
@@ -1421,7 +1547,8 @@ static struct dev_ops zfs_dev_ops = {
};
static struct modldrv zfs_modldrv = {
- &mod_driverops, "ZFS storage pool version 1", &zfs_dev_ops
+ &mod_driverops, "ZFS storage pool version " ZFS_VERSION_STRING,
+ &zfs_dev_ops
};
static struct modlinkage modlinkage = {
diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
index 5abaaa174f..04ada0c8d0 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
@@ -1237,5 +1237,5 @@ static vfsdef_t vfw = {
};
struct modlfs zfs_modlfs = {
- &mod_fsops, "ZFS filesystem version 1", &vfw
+ &mod_fsops, "ZFS filesystem version " ZFS_VERSION_STRING, &vfw
};
diff --git a/usr/src/uts/common/fs/zfs/zvol.c b/usr/src/uts/common/fs/zfs/zvol.c
index 66a8327b51..0b83bd7bd0 100644
--- a/usr/src/uts/common/fs/zfs/zvol.c
+++ b/usr/src/uts/common/fs/zfs/zvol.c
@@ -116,27 +116,27 @@ zvol_size_changed(zvol_state_t *zv, dev_t dev)
}
int
-zvol_check_volsize(zfs_cmd_t *zc, uint64_t blocksize)
+zvol_check_volsize(uint64_t volsize, uint64_t blocksize)
{
- if (zc->zc_volsize == 0)
+ if (volsize == 0)
return (EINVAL);
- if (zc->zc_volsize % blocksize != 0)
+ if (volsize % blocksize != 0)
return (EINVAL);
#ifdef _ILP32
- if (zc->zc_volsize - 1 > SPEC_MAXOFFSET_T)
+ if (volsize - 1 > SPEC_MAXOFFSET_T)
return (EOVERFLOW);
#endif
return (0);
}
int
-zvol_check_volblocksize(zfs_cmd_t *zc)
+zvol_check_volblocksize(uint64_t volblocksize)
{
- if (zc->zc_volblocksize < SPA_MINBLOCKSIZE ||
- zc->zc_volblocksize > SPA_MAXBLOCKSIZE ||
- !ISP2(zc->zc_volblocksize))
+ if (volblocksize < SPA_MINBLOCKSIZE ||
+ volblocksize > SPA_MAXBLOCKSIZE ||
+ !ISP2(volblocksize))
return (EDOM);
return (0);
@@ -151,12 +151,12 @@ zvol_readonly_changed_cb(void *arg, uint64_t newval)
}
int
-zvol_get_stats(zfs_cmd_t *zc, objset_t *os)
+zvol_get_stats(objset_t *os, zvol_stats_t *zvs)
{
int error;
dmu_object_info_t doi;
- error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &zc->zc_volsize);
+ error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &zvs->zv_volsize);
if (error)
return (error);
@@ -164,7 +164,7 @@ zvol_get_stats(zfs_cmd_t *zc, objset_t *os)
error = dmu_object_info(os, ZVOL_OBJ, &doi);
if (error == 0)
- zc->zc_volblocksize = doi.doi_data_block_size;
+ zvs->zv_volblocksize = doi.doi_data_block_size;
return (error);
}
@@ -187,7 +187,7 @@ zvol_minor_alloc(void)
}
static zvol_state_t *
-zvol_minor_lookup(char *name)
+zvol_minor_lookup(const char *name)
{
minor_t minor;
zvol_state_t *zv;
@@ -208,10 +208,26 @@ zvol_minor_lookup(char *name)
void
zvol_create_cb(objset_t *os, void *arg, dmu_tx_t *tx)
{
- zfs_cmd_t *zc = arg;
+ zfs_create_data_t *zc = arg;
int error;
+ uint64_t volblocksize, volsize;
- error = dmu_object_claim(os, ZVOL_OBJ, DMU_OT_ZVOL, zc->zc_volblocksize,
+ VERIFY(nvlist_lookup_uint64(zc->zc_props,
+ zfs_prop_to_name(ZFS_PROP_VOLSIZE), &volsize) == 0);
+ if (nvlist_lookup_uint64(zc->zc_props,
+ zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), &volblocksize) != 0)
+ volblocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
+
+ /*
+ * These properites must be removed from the list so the generic
+ * property setting step won't apply to them.
+ */
+ VERIFY(nvlist_remove_all(zc->zc_props,
+ zfs_prop_to_name(ZFS_PROP_VOLSIZE)) == 0);
+ (void) nvlist_remove_all(zc->zc_props,
+ zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE));
+
+ error = dmu_object_claim(os, ZVOL_OBJ, DMU_OT_ZVOL, volblocksize,
DMU_OT_NONE, 0, tx);
ASSERT(error == 0);
@@ -219,7 +235,7 @@ zvol_create_cb(objset_t *os, void *arg, dmu_tx_t *tx)
DMU_OT_NONE, 0, tx);
ASSERT(error == 0);
- error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1, &zc->zc_volsize, tx);
+ error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize, tx);
ASSERT(error == 0);
}
@@ -284,10 +300,8 @@ zil_replay_func_t *zvol_replay_vector[TX_MAX_TYPE] = {
* Create a minor node for the specified volume.
*/
int
-zvol_create_minor(zfs_cmd_t *zc)
+zvol_create_minor(const char *name, dev_t dev)
{
- char *name = zc->zc_name;
- dev_t dev = zc->zc_dev;
zvol_state_t *zv;
objset_t *os;
uint64_t volsize;
@@ -377,7 +391,8 @@ zvol_create_minor(zfs_cmd_t *zc)
return (EAGAIN);
}
- (void) ddi_prop_update_string(minor, zfs_dip, ZVOL_PROP_NAME, name);
+ (void) ddi_prop_update_string(minor, zfs_dip, ZVOL_PROP_NAME,
+ (char *)name);
(void) sprintf(chrbuf, "%uc,raw", minor);
@@ -431,14 +446,14 @@ zvol_create_minor(zfs_cmd_t *zc)
* Remove minor node for the specified volume.
*/
int
-zvol_remove_minor(zfs_cmd_t *zc)
+zvol_remove_minor(const char *name)
{
zvol_state_t *zv;
char namebuf[30];
mutex_enter(&zvol_state_lock);
- if ((zv = zvol_minor_lookup(zc->zc_name)) == NULL) {
+ if ((zv = zvol_minor_lookup(name)) == NULL) {
mutex_exit(&zvol_state_lock);
return (ENXIO);
}
@@ -472,23 +487,23 @@ zvol_remove_minor(zfs_cmd_t *zc)
}
int
-zvol_set_volsize(zfs_cmd_t *zc)
+zvol_set_volsize(const char *name, dev_t dev, uint64_t volsize)
{
zvol_state_t *zv;
- dev_t dev = zc->zc_dev;
dmu_tx_t *tx;
int error;
dmu_object_info_t doi;
mutex_enter(&zvol_state_lock);
- if ((zv = zvol_minor_lookup(zc->zc_name)) == NULL) {
+ if ((zv = zvol_minor_lookup(name)) == NULL) {
mutex_exit(&zvol_state_lock);
return (ENXIO);
}
if ((error = dmu_object_info(zv->zv_objset, ZVOL_OBJ, &doi)) != 0 ||
- (error = zvol_check_volsize(zc, doi.doi_data_block_size)) != 0) {
+ (error = zvol_check_volsize(volsize,
+ doi.doi_data_block_size)) != 0) {
mutex_exit(&zvol_state_lock);
return (error);
}
@@ -500,7 +515,7 @@ zvol_set_volsize(zfs_cmd_t *zc)
tx = dmu_tx_create(zv->zv_objset);
dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL);
- dmu_tx_hold_free(tx, ZVOL_OBJ, zc->zc_volsize, DMU_OBJECT_END);
+ dmu_tx_hold_free(tx, ZVOL_OBJ, volsize, DMU_OBJECT_END);
error = dmu_tx_assign(tx, TXG_WAIT);
if (error) {
dmu_tx_abort(tx);
@@ -509,16 +524,16 @@ zvol_set_volsize(zfs_cmd_t *zc)
}
error = zap_update(zv->zv_objset, ZVOL_ZAP_OBJ, "size", 8, 1,
- &zc->zc_volsize, tx);
+ &volsize, tx);
if (error == 0) {
- error = dmu_free_range(zv->zv_objset, ZVOL_OBJ, zc->zc_volsize,
+ error = dmu_free_range(zv->zv_objset, ZVOL_OBJ, volsize,
DMU_OBJECT_END, tx);
}
dmu_tx_commit(tx);
if (error == 0) {
- zv->zv_volsize = zc->zc_volsize;
+ zv->zv_volsize = volsize;
zvol_size_changed(zv, dev);
}
@@ -528,7 +543,7 @@ zvol_set_volsize(zfs_cmd_t *zc)
}
int
-zvol_set_volblocksize(zfs_cmd_t *zc)
+zvol_set_volblocksize(const char *name, uint64_t volblocksize)
{
zvol_state_t *zv;
dmu_tx_t *tx;
@@ -536,7 +551,7 @@ zvol_set_volblocksize(zfs_cmd_t *zc)
mutex_enter(&zvol_state_lock);
- if ((zv = zvol_minor_lookup(zc->zc_name)) == NULL) {
+ if ((zv = zvol_minor_lookup(name)) == NULL) {
mutex_exit(&zvol_state_lock);
return (ENXIO);
}
@@ -553,7 +568,7 @@ zvol_set_volblocksize(zfs_cmd_t *zc)
dmu_tx_abort(tx);
} else {
error = dmu_object_set_blocksize(zv->zv_objset, ZVOL_OBJ,
- zc->zc_volblocksize, 0, tx);
+ volblocksize, 0, tx);
if (error == ENOTSUP)
error = EBUSY;
dmu_tx_commit(tx);
diff --git a/usr/src/uts/common/sys/fs/zfs.h b/usr/src/uts/common/sys/fs/zfs.h
index 2af99527fd..b882715516 100644
--- a/usr/src/uts/common/sys/fs/zfs.h
+++ b/usr/src/uts/common/sys/fs/zfs.h
@@ -84,6 +84,7 @@ typedef enum {
ZFS_PROP_SNAPDIR,
ZFS_PROP_ACLMODE,
ZFS_PROP_ACLINHERIT,
+ ZFS_PROP_CANMOUNT,
/*
* The following properties are not exposed to the user, but are
* accessible by libzfs clients.
@@ -102,10 +103,12 @@ typedef enum {
* The following functions are shared between libzfs and the kernel.
*/
zfs_prop_t zfs_name_to_prop(const char *);
+boolean_t zfs_prop_user(const char *);
int zfs_prop_readonly(zfs_prop_t);
const char *zfs_prop_default_string(zfs_prop_t);
+const char *zfs_prop_to_name(zfs_prop_t);
uint64_t zfs_prop_default_numeric(zfs_prop_t);
-
+int zfs_prop_inheritable(zfs_prop_t);
/*
* On-disk version number.
@@ -114,6 +117,7 @@ uint64_t zfs_prop_default_numeric(zfs_prop_t);
#define ZFS_VERSION_2 2ULL
#define ZFS_VERSION_3 3ULL
#define ZFS_VERSION ZFS_VERSION_3
+#define ZFS_VERSION_STRING "3"
/*
* Symbolic names for the changes that caused a ZFS_VERSION switch.
@@ -332,10 +336,6 @@ typedef enum zfs_ioc {
ZFS_IOC_DATASET_LIST_NEXT,
ZFS_IOC_SNAPSHOT_LIST_NEXT,
ZFS_IOC_SET_PROP,
- ZFS_IOC_SET_QUOTA,
- ZFS_IOC_SET_RESERVATION,
- ZFS_IOC_SET_VOLSIZE,
- ZFS_IOC_SET_VOLBLOCKSIZE,
ZFS_IOC_CREATE_MINOR,
ZFS_IOC_REMOVE_MINOR,
ZFS_IOC_CREATE,
@@ -365,6 +365,13 @@ typedef enum {
SPA_LOAD_TRYIMPORT /* tryimport in progress */
} spa_load_state_t;
+/*
+ * Bookmark name values.
+ */
+#define ZPOOL_ERR_DATASET "dataset"
+#define ZPOOL_ERR_OBJECT "object"
+#define ZPOOL_ERR_RANGE "range"
+
#ifdef __cplusplus
}
#endif