summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/cmd/mdb/common/modules/zfs/zfs.c194
-rw-r--r--usr/src/cmd/zdb/zdb.c1
-rw-r--r--usr/src/cmd/zfs/zfs_main.c52
-rw-r--r--usr/src/cmd/zpool/zpool_main.c56
-rw-r--r--usr/src/common/zfs/zfs_deleg.c121
-rw-r--r--usr/src/common/zfs/zfs_deleg.h4
-rw-r--r--usr/src/common/zfs/zfs_prop.c603
-rw-r--r--usr/src/common/zfs/zfs_prop.h10
-rw-r--r--usr/src/lib/libzfs/common/libzfs.h1
-rw-r--r--usr/src/lib/libzfs/common/libzfs_dataset.c121
-rw-r--r--usr/src/lib/libzfs/common/libzfs_util.c6
-rw-r--r--usr/src/lib/libzfs_jni/common/libzfs_jni_main.c13
-rw-r--r--usr/src/lib/libzfs_jni/common/libzfs_jni_property.c57
-rw-r--r--usr/src/uts/common/Makefile.files1
-rw-r--r--usr/src/uts/common/fs/zfs/dmu_objset.c28
-rw-r--r--usr/src/uts/common/fs/zfs/dnode_sync.c2
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_dataset.c29
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_deleg.c76
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_prop.c2
-rw-r--r--usr/src/uts/common/fs/zfs/refcount.c11
-rw-r--r--usr/src/uts/common/fs/zfs/rprwlock.c118
-rw-r--r--usr/src/uts/common/fs/zfs/spa.c3
-rw-r--r--usr/src/uts/common/fs/zfs/spa_config.c3
-rw-r--r--usr/src/uts/common/fs/zfs/spa_misc.c79
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dmu.h2
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dmu_objset.h2
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dnode.h2
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dsl_dataset.h4
-rw-r--r--usr/src/uts/common/fs/zfs/sys/dsl_deleg.h35
-rw-r--r--usr/src/uts/common/fs/zfs/sys/refcount.h4
-rw-r--r--usr/src/uts/common/fs/zfs/sys/rprwlock.h61
-rw-r--r--usr/src/uts/common/fs/zfs/sys/spa_impl.h17
-rw-r--r--usr/src/uts/common/fs/zfs/sys/unique.h13
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h2
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h7
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_znode.h8
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zvol.h4
-rw-r--r--usr/src/uts/common/fs/zfs/unique.c16
-rw-r--r--usr/src/uts/common/fs/zfs/vdev_label.c3
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ioctl.c58
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vfsops.c217
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vnops.c8
-rw-r--r--usr/src/uts/common/fs/zfs/zvol.c12
-rw-r--r--usr/src/uts/common/sys/fs/zfs.h10
44 files changed, 992 insertions, 1084 deletions
diff --git a/usr/src/cmd/mdb/common/modules/zfs/zfs.c b/usr/src/cmd/mdb/common/modules/zfs/zfs.c
index 11e8826e84..1e28658a47 100644
--- a/usr/src/cmd/mdb/common/modules/zfs/zfs.c
+++ b/usr/src/cmd/mdb/common/modules/zfs/zfs.c
@@ -770,54 +770,26 @@ abuf_find(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
return (DCMD_OK);
}
-void
-abuf_help(void)
-{
- mdb_printf("::abuf_find dva_word[0] dva_word[1]\n");
-}
-
/*ARGSUSED*/
static int
arc_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
kstat_named_t *stats;
GElf_Sym sym;
- int nstats, i, j;
+ int nstats, i;
uint_t opt_a = FALSE;
+ uint_t opt_b = FALSE;
+ uint_t shift = 0;
+ const char *suffix;
- /*
- * In its default mode, ::arc prints exactly what one would see with
- * the legacy "arc::print". The legacy[] array tracks the order of
- * the legacy "arc" structure -- and whether the variable can be found
- * in a global variable or within the arc_stats (the default).
- */
- struct {
- const char *name;
- const char *var;
- } legacy[] = {
- { "anon", "arc_anon" },
- { "mru", "arc_mru" },
- { "mru_ghost", "arc_mru_ghost" },
- { "mfu", "arc_mfu" },
- { "mfu_ghost", "arc_mfu_ghost" },
- { "size" },
- { "p" },
- { "c" },
- { "c_min" },
- { "c_max" },
- { "hits" },
- { "misses" },
- { "deleted" },
- { "recycle_miss" },
- { "mutex_miss" },
- { "evict_skip" },
- { "hash_elements" },
- { "hash_elements_max" },
- { "hash_collisions" },
- { "hash_chains" },
- { "hash_chain_max" },
- { "no_grow", "arc_no_grow" },
- { NULL }
+ static const char *bytestats[] = {
+ "p", "c", "c_min", "c_max", "size", NULL
+ };
+
+ static const char *extras[] = {
+ "arc_no_grow", "arc_tempreserve",
+ "arc_meta_used", "arc_meta_limit", "arc_meta_max",
+ NULL
};
if (mdb_lookup_by_name("arc_stats", &sym) == -1) {
@@ -834,82 +806,85 @@ arc_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
nstats = sym.st_size / sizeof (kstat_named_t);
- if (mdb_getopts(argc, argv, 'a',
- MDB_OPT_SETBITS, TRUE, &opt_a, NULL) != argc)
+ /* NB: -a / opt_a are ignored for backwards compatability */
+ if (mdb_getopts(argc, argv,
+ 'a', MDB_OPT_SETBITS, TRUE, &opt_a,
+ 'b', MDB_OPT_SETBITS, TRUE, &opt_b,
+ 'k', MDB_OPT_SETBITS, 10, &shift,
+ 'm', MDB_OPT_SETBITS, 20, &shift,
+ 'g', MDB_OPT_SETBITS, 30, &shift,
+ NULL) != argc)
return (DCMD_USAGE);
- mdb_printf("{\n");
+ if (!opt_b && !shift)
+ shift = 20;
+
+ switch (shift) {
+ case 0:
+ suffix = "B";
+ break;
+ case 10:
+ suffix = "KB";
+ break;
+ case 20:
+ suffix = "MB";
+ break;
+ case 30:
+ suffix = "GB";
+ break;
+ default:
+ suffix = "XX";
+ }
+
+ for (i = 0; i < nstats; i++) {
+ int j;
+ boolean_t bytes = B_FALSE;
+
+ for (j = 0; bytestats[j]; j++) {
+ if (strcmp(stats[i].name, bytestats[j]) == 0) {
+ bytes = B_TRUE;
+ break;
+ }
+ }
- if (opt_a) {
- for (i = 0; i < nstats; i++) {
- mdb_printf(" %s = 0x%llx\n", stats[i].name,
+ if (bytes) {
+ mdb_printf("%-25s = %9llu %s\n", stats[i].name,
+ stats[i].value.ui64 >> shift, suffix);
+ } else {
+ mdb_printf("%-25s = %9llu\n", stats[i].name,
stats[i].value.ui64);
}
-
- mdb_printf("}\n");
- return (DCMD_OK);
}
- for (i = 0; legacy[i].name != NULL; i++) {
- if (legacy[i].var != NULL) {
- uint64_t buf;
-
- if (mdb_lookup_by_name(legacy[i].var, &sym) == -1) {
- mdb_warn("failed to find '%s'", legacy[i].var);
- return (DCMD_ERR);
- }
-
- if (sym.st_size != sizeof (uint64_t) &&
- sym.st_size != sizeof (uint32_t)) {
- mdb_warn("expected scalar for legacy "
- "variable '%s'\n", legacy[i].var);
- return (DCMD_ERR);
- }
-
- if (mdb_vread(&buf, sym.st_size, sym.st_value) == -1) {
- mdb_warn("couldn't read '%s'", legacy[i].var);
- return (DCMD_ERR);
- }
-
- mdb_printf(" %s = ", legacy[i].name);
+ for (i = 0; extras[i]; i++) {
+ uint64_t buf;
- if (sym.st_size == sizeof (uint64_t))
- mdb_printf("%a\n", buf);
-
- if (sym.st_size == sizeof (uint32_t))
- mdb_printf("%d\n", *((uint32_t *)&buf));
-
- continue;
+ if (mdb_lookup_by_name(extras[i], &sym) == -1) {
+ mdb_warn("failed to find '%s'", extras[i]);
+ return (DCMD_ERR);
}
- for (j = 0; j < nstats; j++) {
- if (strcmp(legacy[i].name, stats[j].name) != 0)
- continue;
-
- mdb_printf(" %s = ", stats[j].name);
-
- if (stats[j].value.ui64 == 0) {
- /*
- * To remain completely output compatible with
- * the legacy arc::print, we print 0 not as
- * "0x0" but rather 0.
- */
- mdb_printf("0\n");
- } else {
- mdb_printf("0x%llx\n", stats[j].value.ui64);
- }
-
- break;
+ if (sym.st_size != sizeof (uint64_t) &&
+ sym.st_size != sizeof (uint32_t)) {
+ mdb_warn("expected scalar for variable '%s'\n",
+ extras[i]);
+ return (DCMD_ERR);
}
- if (j == nstats) {
- mdb_warn("couldn't find statistic in 'arc_stats' "
- "for field '%s'\n", legacy[i].name);
+ if (mdb_vread(&buf, sym.st_size, sym.st_value) == -1) {
+ mdb_warn("couldn't read '%s'", extras[i]);
+ return (DCMD_ERR);
}
- }
- mdb_printf("}\n");
+ mdb_printf("%-25s = ", extras[i]);
+
+ /* NB: all the 64-bit extras happen to be byte counts */
+ if (sym.st_size == sizeof (uint64_t))
+ mdb_printf("%9llu %s\n", buf >> shift, suffix);
+ if (sym.st_size == sizeof (uint32_t))
+ mdb_printf("%9d\n", *((uint32_t *)&buf));
+ }
return (DCMD_OK);
}
@@ -1035,14 +1010,6 @@ spa_print_config(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
0, NULL));
}
-void
-vdev_help(void)
-{
- mdb_printf("[vdev_t*]::vdev [-er]\n"
- "\t-> -e display vdev stats\n"
- "\t-> -r recursive (visit all children)\n");
-}
-
/*
* ::vdev
*
@@ -1920,14 +1887,14 @@ zio_walk_root_step(mdb_walk_state_t *wsp)
*/
static const mdb_dcmd_t dcmds[] = {
- { "arc", "[-a]", "print ARC variables", arc_print },
+ { "arc", "[-bkmg]", "print ARC variables", arc_print },
{ "blkptr", ":", "print blkptr_t", blkptr },
{ "dbuf", ":", "print dmu_buf_impl_t", dbuf },
{ "dbuf_stats", ":", "dbuf stats", dbuf_stats },
{ "dbufs",
"\t[-O objset_t*] [-n objset_name | \"mos\"] [-o object | \"mdn\"] \n"
"\t[-l level] [-b blkid | \"bonus\"]",
- "find dmu_buf_impl_t's that meet criterion", dbufs },
+ "find dmu_buf_impl_t's that match specified criteria", dbufs },
{ "abuf_find", "dva_word[0] dva_word[1]",
"find arc_buf_hdr_t of a specified DVA",
abuf_find },
@@ -1936,7 +1903,10 @@ static const mdb_dcmd_t dcmds[] = {
{ "spa_verify", ":", "verify spa_t consistency", spa_verify },
{ "spa_space", ":[-b]", "print spa_t on-disk space usage", spa_space },
{ "spa_vdevs", ":", "given a spa_t, print vdev summary", spa_vdevs },
- { "vdev", ":[-re]", "vdev_t summary", vdev_print },
+ { "vdev", ":[-re]\n"
+ "\t-r display recursively\n"
+ "\t-e print statistics\n",
+ "vdev_t summary", vdev_print },
{ "zio", ":", "zio_t summary", zio_print },
{ "zio_state", "?", "print out all zio_t structures on system or "
"for a particular pool", zio_state },
diff --git a/usr/src/cmd/zdb/zdb.c b/usr/src/cmd/zdb/zdb.c
index 4279e64abd..12e49c1db6 100644
--- a/usr/src/cmd/zdb/zdb.c
+++ b/usr/src/cmd/zdb/zdb.c
@@ -2287,6 +2287,7 @@ main(int argc, char **argv)
kernel_init(FREAD);
g_zfs = libzfs_init();
+ ASSERT(g_zfs != NULL);
/*
* Disable vdev caching. If we don't do this, live pool traversal
diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c
index 044c52e650..438c0bbf74 100644
--- a/usr/src/cmd/zfs/zfs_main.c
+++ b/usr/src/cmd/zfs/zfs_main.c
@@ -380,7 +380,7 @@ usage(boolean_t requested)
"PROPERTY", "EDIT", "INHERIT", "VALUES");
/* Iterate over all properties */
- (void) zfs_prop_iter_ordered(usage_prop_cb, fp, B_FALSE);
+ (void) zfs_prop_iter_ordered(usage_prop_cb, fp);
(void) fprintf(fp, gettext("\nSizes are specified in bytes "
"with standard units such as K, M, G, etc.\n"));
@@ -3829,17 +3829,6 @@ find_command_idx(char *command, int *idx)
return (1);
}
-zfs_prop_t
-propset_cb(zfs_prop_t prop, void *data)
-{
- char *cmdname = (char *)data;
-
- if (strcmp(cmdname, zfs_prop_to_name(prop)) == 0)
- return (prop);
-
- return (ZFS_PROP_CONT);
-}
-
int
main(int argc, char **argv)
{
@@ -3847,8 +3836,6 @@ main(int argc, char **argv)
int i;
char *progname;
char *cmdname;
- char *str;
- boolean_t found = B_FALSE;
(void) setlocale(LC_ALL, "");
(void) textdomain(TEXT_DOMAIN);
@@ -3927,38 +3914,11 @@ main(int argc, char **argv)
if (find_command_idx(cmdname, &i) == 0) {
current_command = &command_table[i];
ret = command_table[i].func(argc - 1, argv + 1);
- found = B_TRUE;
- }
-
- /*
- * Check and see if they are doing property=value
- */
- if (found == B_FALSE &&
- ((str = strchr(cmdname, '=')) != NULL)) {
- *str = '\0';
- if (zfs_prop_iter(propset_cb, cmdname,
- B_FALSE) != ZFS_PROP_INVAL)
- found = B_TRUE;
-
- if (found == B_FALSE && zfs_prop_user(cmdname))
- found = B_TRUE;
-
- if (found == B_TRUE &&
- find_command_idx("set", &i) == 0) {
- *str = '=';
- current_command = &command_table[i];
- ret = command_table[i].func(argc, argv);
- } else {
- (void) fprintf(stderr,
- gettext("invalid property '%s'\n"),
- cmdname);
- found = B_TRUE;
- ret = 1;
- }
-
- }
-
- if (found == B_FALSE) {
+ } else if (strchr(cmdname, '=') != NULL) {
+ verify(find_command_idx("set", &i) == 0);
+ current_command = &command_table[i];
+ ret = command_table[i].func(argc, argv);
+ } else {
(void) fprintf(stderr, gettext("unrecognized "
"command '%s'\n"), cmdname);
usage(B_FALSE);
diff --git a/usr/src/cmd/zpool/zpool_main.c b/usr/src/cmd/zpool/zpool_main.c
index 690a5807d9..d34ebf840a 100644
--- a/usr/src/cmd/zpool/zpool_main.c
+++ b/usr/src/cmd/zpool/zpool_main.c
@@ -343,7 +343,7 @@ usage(boolean_t requested)
"PROPERTY", "VALUES");
/* Iterate over all properties */
- (void) zpool_prop_iter(print_prop_cb, fp, B_FALSE);
+ (void) zpool_prop_iter(print_prop_cb, fp);
}
/*
@@ -3759,25 +3759,12 @@ find_command_idx(char *command, int *idx)
return (1);
}
-zpool_prop_t
-propset_cb(zpool_prop_t prop, void *data)
-{
- char *cmdname = (char *)data;
-
- if (strcmp(cmdname, zpool_prop_to_name(prop)) == 0)
- return (prop);
-
- return (ZFS_PROP_CONT);
-}
-
int
main(int argc, char **argv)
{
int ret;
int i;
char *cmdname;
- boolean_t found = B_FALSE;
- char *str;
(void) setlocale(LC_ALL, "");
(void) textdomain(TEXT_DOMAIN);
@@ -3820,41 +3807,20 @@ main(int argc, char **argv)
if (find_command_idx(cmdname, &i) == 0) {
current_command = &command_table[i];
ret = command_table[i].func(argc - 1, argv + 1);
- found = B_TRUE;
- }
-
- /*
- * 'freeze' is a vile debugging abomination, so we treat it as such.
- */
- if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
+ } else if (strchr(cmdname, '=')) {
+ verify(find_command_idx("set", &i) == 0);
+ current_command = &command_table[i];
+ ret = command_table[i].func(argc, argv);
+ } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
+ /*
+ * 'freeze' is a vile debugging abomination, so we treat
+ * it as such.
+ */
char buf[16384];
int fd = open(ZFS_DEV, O_RDWR);
(void) strcpy((void *)buf, argv[2]);
return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
- }
-
- /* is this a zpool property=value */
- if (found == B_FALSE && ((str = strchr(cmdname, '=')) != NULL)) {
- *str = '\0';
- if (zpool_prop_iter(propset_cb, cmdname,
- B_FALSE) != ZFS_PROP_INVAL) {
- if (find_command_idx("set", &i) == 0) {
- *str = '=';
- current_command = &command_table[i];
- ret = command_table[i].func(argc, argv);
- found = B_TRUE;
- }
- }
-
- if (found == B_FALSE) {
- *str = '=';
- (void) fprintf(stderr,
- gettext("invalid property '%s'\n"), cmdname);
- found = B_TRUE;
- }
- }
-
- if (found == B_FALSE) {
+ } else {
(void) fprintf(stderr, gettext("unrecognized "
"command '%s'\n"), cmdname);
usage(B_FALSE);
diff --git a/usr/src/common/zfs/zfs_deleg.c b/usr/src/common/zfs/zfs_deleg.c
index d7c3046572..31ea16b29c 100644
--- a/usr/src/common/zfs/zfs_deleg.c
+++ b/usr/src/common/zfs/zfs_deleg.c
@@ -37,7 +37,9 @@
#include <libnvpair.h>
#include <ctype.h>
#endif
+/* XXX includes zfs_context.h, so why bother with the above? */
#include <sys/dsl_deleg.h>
+#include "zfs_prop.h"
#include "zfs_deleg.h"
#include "zfs_namecheck.h"
@@ -57,108 +59,84 @@ char *zfs_deleg_perm_tab[] = {
ZFS_DELEG_PERM_SHARE,
ZFS_DELEG_PERM_SEND,
ZFS_DELEG_PERM_RECEIVE,
- ZFS_DELEG_PERM_QUOTA,
- ZFS_DELEG_PERM_RESERVATION,
- ZFS_DELEG_PERM_VOLSIZE,
- ZFS_DELEG_PERM_RECORDSIZE,
- ZFS_DELEG_PERM_MOUNTPOINT,
- ZFS_DELEG_PERM_SHARENFS,
- ZFS_DELEG_PERM_CHECKSUM,
- ZFS_DELEG_PERM_COMPRESSION,
- ZFS_DELEG_PERM_ATIME,
- ZFS_DELEG_PERM_DEVICES,
- ZFS_DELEG_PERM_EXEC,
- ZFS_DELEG_PERM_SETUID,
- ZFS_DELEG_PERM_READONLY,
- ZFS_DELEG_PERM_ZONED,
- ZFS_DELEG_PERM_SNAPDIR,
- ZFS_DELEG_PERM_ACLMODE,
- ZFS_DELEG_PERM_ACLINHERIT,
ZFS_DELEG_PERM_ALLOW,
- ZFS_DELEG_PERM_CANMOUNT,
ZFS_DELEG_PERM_USERPROP,
- ZFS_DELEG_PERM_SHAREISCSI,
- ZFS_DELEG_PERM_XATTR,
- ZFS_DELEG_PERM_COPIES,
- ZFS_DELEG_PERM_VERSION,
NULL
};
-int
-zfs_deleg_type(char *name)
+static int
+zfs_valid_permission_name(const char *perm)
{
- return (name[0]);
+ if (zfs_deleg_canonicalize_perm(perm))
+ return (0);
+
+ return (permset_namecheck(perm, NULL, NULL));
}
-static int
-zfs_valid_permission_name(char *perm)
+const char *
+zfs_deleg_canonicalize_perm(const char *perm)
{
int i;
+ zfs_prop_t prop;
+
for (i = 0; zfs_deleg_perm_tab[i] != NULL; i++) {
if (strcmp(perm, zfs_deleg_perm_tab[i]) == 0)
- return (0);
+ return (perm);
}
- return (permset_namecheck(perm, NULL, NULL));
+ prop = zfs_name_to_prop(perm);
+ if (prop != ZFS_PROP_INVAL && zfs_prop_delegatable(prop))
+ return (zfs_prop_to_name(prop));
+ return (NULL);
+
}
static int
zfs_validate_who(char *who)
{
- int error = 0;
char *p;
- switch (zfs_deleg_type(who)) {
+ if (who[2] != ZFS_DELEG_FIELD_SEP_CHR)
+ return (-1);
+
+ switch (who[0]) {
case ZFS_DELEG_USER:
case ZFS_DELEG_GROUP:
case ZFS_DELEG_USER_SETS:
case ZFS_DELEG_GROUP_SETS:
- if ((who[1] != 'l' || who[1] != 'd') &&
- (who[2] != ZFS_DELEG_FIELD_SEP_CHR)) {
- error = -1;
- break;
- }
-
- for (p = &who[3]; p && *p; p++)
- if (!isdigit(*p)) {
- error = -1;
- }
+ if (who[1] != ZFS_DELEG_LOCAL && who[1] != ZFS_DELEG_DESCENDENT)
+ return (-1);
+ for (p = &who[3]; *p; p++)
+ if (!isdigit(*p))
+ return (-1);
break;
+
case ZFS_DELEG_NAMED_SET:
case ZFS_DELEG_NAMED_SET_SETS:
- error = permset_namecheck(&who[3], NULL, NULL);
- break;
+ if (who[1] != ZFS_DELEG_NA)
+ return (-1);
+ return (permset_namecheck(&who[3], NULL, NULL));
case ZFS_DELEG_CREATE:
case ZFS_DELEG_CREATE_SETS:
- case ZFS_DELEG_EVERYONE:
- case ZFS_DELEG_EVERYONE_SETS:
+ if (who[1] != ZFS_DELEG_NA)
+ return (-1);
if (who[3] != '\0')
- error = -1;
+ return (-1);
break;
- default:
- error = -1;
- }
- return (error);
-}
-
-static int
-zfs_validate_iflags(char *who)
-{
- switch (zfs_deleg_type(who)) {
- case ZFS_DELEG_NAMED_SET:
- case ZFS_DELEG_NAMED_SET_SETS:
- case ZFS_DELEG_CREATE:
- case ZFS_DELEG_CREATE_SETS:
- if (who[1] != '-')
+ case ZFS_DELEG_EVERYONE:
+ case ZFS_DELEG_EVERYONE_SETS:
+ if (who[1] != ZFS_DELEG_LOCAL && who[1] != ZFS_DELEG_DESCENDENT)
return (-1);
- break;
- default:
- if (who[1] != 'l' && who[1] != 'd')
+ if (who[3] != '\0')
return (-1);
break;
+
+ default:
+ return (-1);
}
+
return (0);
}
@@ -180,9 +158,6 @@ zfs_deleg_verify_nvlist(nvlist_t *nvp)
if (zfs_validate_who(nvpair_name(who)))
return (-1);
- if (zfs_validate_iflags(nvpair_name(who)))
- return (-1);
-
error = nvlist_lookup_nvlist(nvp, nvpair_name(who), &perms);
if (error && error != ENOENT)
@@ -197,9 +172,8 @@ zfs_deleg_verify_nvlist(nvlist_t *nvp)
do {
error = zfs_valid_permission_name(
nvpair_name(perm_name));
- if (error) {
+ if (error)
return (-1);
- }
} while (perm_name = nvlist_next_nvpair(perms, perm_name));
} while (who = nvlist_next_nvpair(nvp, who));
return (0);
@@ -220,7 +194,8 @@ zfs_deleg_verify_nvlist(nvlist_t *nvp)
* data - is either a permission set name or a 64 bit uid/gid.
*/
void
-zfs_deleg_whokey(char *attr, char type, char inheritchr, void *data)
+zfs_deleg_whokey(char *attr, zfs_deleg_who_type_t type,
+ char inheritchr, void *data)
{
int len = ZFS_MAX_DELEG_NAME;
uint64_t *id = data;
@@ -243,8 +218,12 @@ zfs_deleg_whokey(char *attr, char type, char inheritchr, void *data)
(void) snprintf(attr, len, "%c-%c", type,
ZFS_DELEG_FIELD_SEP_CHR);
break;
- default:
+ case ZFS_DELEG_EVERYONE:
+ case ZFS_DELEG_EVERYONE_SETS:
(void) snprintf(attr, len, "%c%c%c", type, inheritchr,
ZFS_DELEG_FIELD_SEP_CHR);
+ break;
+ default:
+ ASSERT(!"bad zfs_deleg_who_type_t");
}
}
diff --git a/usr/src/common/zfs/zfs_deleg.h b/usr/src/common/zfs/zfs_deleg.h
index 9a5daf2438..ef6b53473b 100644
--- a/usr/src/common/zfs/zfs_deleg.h
+++ b/usr/src/common/zfs/zfs_deleg.h
@@ -47,11 +47,11 @@ extern "C" {
#define ZFS_DELEG_NA '-'
extern char *zfs_deleg_perm_tab[];
-int zfs_deleg_type(char *attr);
int zfs_deleg_verify_nvlist(nvlist_t *nvlist);
-void zfs_deleg_whokey(char *attr, char type,
+void zfs_deleg_whokey(char *attr, zfs_deleg_who_type_t type,
char checkflag, void *data);
+const char *zfs_deleg_canonicalize_perm(const char *perm);
#ifdef __cplusplus
}
diff --git a/usr/src/common/zfs/zfs_prop.c b/usr/src/common/zfs/zfs_prop.c
index d772baa470..408ec4be09 100644
--- a/usr/src/common/zfs/zfs_prop.c
+++ b/usr/src/common/zfs/zfs_prop.c
@@ -25,28 +25,6 @@
#pragma ident "%Z%%M% %I% %E% SMI"
-/*
- * Master property table.
- *
- * This table keeps track of all the properties supported by ZFS, and their
- * various attributes. Not all of these are needed by the kernel, and several
- * are only used by a single libzfs client. But having them here centralizes
- * all property information in one location.
- *
- * name The human-readable string representing this property
- * proptype Basic type (string, boolean, number)
- * default Default value for the property. Sadly, C only allows
- * you to initialize the first member of a union, so we
- * have two default members for each property.
- * attr Attributes (readonly, inheritable) for the property
- * types Valid dataset types to which this applies
- * values String describing acceptable values for the property
- * colname The column header for 'zfs list'
- * colfmt The column formatting for 'zfs list'
- *
- * This table must match the order of property types in libzfs.h.
- */
-
#include <sys/zio.h>
#include <sys/spa.h>
#include <sys/zfs_acl.h>
@@ -66,156 +44,280 @@
#endif
typedef enum {
- prop_default,
- prop_readonly,
- prop_inherit
+ PROP_DEFAULT,
+ PROP_READONLY,
+ PROP_INHERIT
} prop_attr_t;
+typedef struct zfs_index {
+ const char *name;
+ uint64_t index;
+} zfs_index_t;
+
typedef struct {
- const char *pd_name;
- zfs_proptype_t pd_proptype;
- uint64_t pd_numdefault;
- const char *pd_strdefault;
- prop_attr_t pd_attr;
- int pd_types;
- const char *pd_values;
- const char *pd_colname;
- boolean_t pd_rightalign;
- boolean_t pd_visible;
- const char *pd_perm;
+ const char *pd_name; /* human-readable property name */
+ zfs_proptype_t pd_proptype; /* string, boolean, index, number */
+ const char *pd_strdefault; /* default for strings */
+ uint64_t pd_numdefault; /* for boolean / index / number */
+ prop_attr_t pd_attr; /* default, readonly, inherit */
+ int pd_types; /* bitfield of valid dataset types */
+ /* fs | vol | snap; or pool */
+ const char *pd_values; /* string telling acceptable values */
+ const char *pd_colname; /* column header for "zfs list" */
+ boolean_t pd_rightalign; /* column alignment for "zfs list" */
+ boolean_t pd_visible; /* do we list this property with the */
+ /* "zfs get" help message */
+ const zfs_index_t *pd_table; /* for index properties, a table */
+ /* defining the possible values */
} prop_desc_t;
-static prop_desc_t zfs_prop_table[] = {
- { "type", prop_type_string, 0, NULL, prop_readonly,
- ZFS_TYPE_ANY, "filesystem | volume | snapshot", "TYPE", B_TRUE,
- B_TRUE, ZFS_DELEG_PERM_NONE },
- { "creation", prop_type_number, 0, NULL, prop_readonly,
- ZFS_TYPE_ANY, "<date>", "CREATION", B_FALSE, B_TRUE,
- ZFS_DELEG_PERM_NONE },
- { "used", prop_type_number, 0, NULL, prop_readonly,
- ZFS_TYPE_ANY, "<size>", "USED", B_TRUE, B_TRUE,
- ZFS_DELEG_PERM_NONE },
- { "available", prop_type_number, 0, NULL, prop_readonly,
- ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>", "AVAIL", B_TRUE,
- B_TRUE, ZFS_DELEG_PERM_NONE },
- { "referenced", prop_type_number, 0, NULL, prop_readonly,
- ZFS_TYPE_ANY,
- "<size>", "REFER", B_TRUE, B_TRUE, ZFS_DELEG_PERM_NONE },
- { "compressratio", prop_type_number, 0, NULL, prop_readonly,
- ZFS_TYPE_ANY, "<1.00x or higher if compressed>", "RATIO", B_TRUE,
- B_TRUE, ZFS_DELEG_PERM_NONE },
- { "mounted", prop_type_boolean, 0, NULL, prop_readonly,
- ZFS_TYPE_FILESYSTEM, "yes | no | -", "MOUNTED", B_TRUE, B_TRUE,
- ZFS_DELEG_PERM_NONE },
- { "origin", prop_type_string, 0, NULL, prop_readonly,
- ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<snapshot>", "ORIGIN",
- B_FALSE, B_TRUE, ZFS_DELEG_PERM_NONE },
- { "quota", prop_type_number, 0, NULL, prop_default,
- ZFS_TYPE_FILESYSTEM, "<size> | none", "QUOTA", B_TRUE, B_TRUE,
- ZFS_DELEG_PERM_QUOTA },
- { "reservation", prop_type_number, 0, NULL, prop_default,
+static prop_desc_t zfs_prop_table[ZFS_NUM_PROPS];
+
+static void
+register_impl(zfs_prop_t prop, const char *name, zfs_proptype_t type,
+ uint64_t numdefault, const char *strdefault, prop_attr_t attr,
+ int objset_types, const char *values, const char *colname,
+ boolean_t rightalign, boolean_t visible, const zfs_index_t *table)
+{
+ prop_desc_t *pd = &zfs_prop_table[prop];
+
+ ASSERT(pd->pd_name == NULL || pd->pd_name == name);
+
+ pd->pd_name = name;
+ pd->pd_proptype = type;
+ pd->pd_numdefault = numdefault;
+ pd->pd_strdefault = strdefault;
+ pd->pd_attr = attr;
+ pd->pd_types = objset_types;
+ pd->pd_values = values;
+ pd->pd_colname = colname;
+ pd->pd_rightalign = rightalign;
+ pd->pd_visible = visible;
+ pd->pd_table = table;
+}
+
+static void
+register_string(zfs_prop_t prop, const char *name, const char *def,
+ prop_attr_t attr, int objset_types, const char *values,
+ const char *colname)
+{
+ register_impl(prop, name, PROP_TYPE_STRING, 0, def, attr,
+ objset_types, values, colname, B_FALSE, B_TRUE, NULL);
+
+}
+
+static void
+register_number(zfs_prop_t prop, const char *name, uint64_t def,
+ prop_attr_t attr, int objset_types, const char *values, const char *colname)
+{
+ register_impl(prop, name, PROP_TYPE_NUMBER, def, NULL, attr,
+ objset_types, values, colname, B_TRUE, B_TRUE, NULL);
+}
+
+static void
+register_boolean(zfs_prop_t prop, const char *name, uint64_t def,
+ prop_attr_t attr, int objset_types, const char *values, const char *colname)
+{
+ register_impl(prop, name, PROP_TYPE_BOOLEAN, def, NULL, attr,
+ objset_types, values, colname, B_TRUE, B_TRUE, NULL);
+}
+
+static void
+register_index(zfs_prop_t prop, const char *name, uint64_t def,
+ int objset_types, const char *values, const char *colname,
+ const zfs_index_t *table)
+{
+ register_impl(prop, name, PROP_TYPE_INDEX, def, NULL, PROP_INHERIT,
+ objset_types, values, colname, B_TRUE, B_TRUE, table);
+}
+
+static void
+register_hidden(zfs_prop_t prop, const char *name, zfs_proptype_t type,
+ prop_attr_t attr, int objset_types, const char *colname)
+{
+ register_impl(prop, name, type, 0, NULL, attr,
+ objset_types, NULL, colname, B_FALSE, B_FALSE, NULL);
+}
+
+void
+zfs_prop_init(void)
+{
+ 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 },
+ { "gzip", ZIO_COMPRESS_GZIP_6 }, /* gzip default */
+ { "gzip-1", ZIO_COMPRESS_GZIP_1 },
+ { "gzip-2", ZIO_COMPRESS_GZIP_2 },
+ { "gzip-3", ZIO_COMPRESS_GZIP_3 },
+ { "gzip-4", ZIO_COMPRESS_GZIP_4 },
+ { "gzip-5", ZIO_COMPRESS_GZIP_5 },
+ { "gzip-6", ZIO_COMPRESS_GZIP_6 },
+ { "gzip-7", ZIO_COMPRESS_GZIP_7 },
+ { "gzip-8", ZIO_COMPRESS_GZIP_8 },
+ { "gzip-9", ZIO_COMPRESS_GZIP_9 },
+ { 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 copies_table[] = {
+ { "1", 1 },
+ { "2", 2 },
+ { "3", 3 },
+ { NULL }
+ };
+
+ static zfs_index_t version_table[] = {
+ { "1", 1 },
+ { "2", 2 },
+ { "current", ZPL_VERSION },
+ { NULL }
+ };
+
+ /* inherit index properties */
+ register_index(ZFS_PROP_CHECKSUM, "checksum", ZIO_CHECKSUM_DEFAULT,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "<size> | none", "RESERV", B_TRUE, B_TRUE,
- ZFS_DELEG_PERM_RESERVATION },
- { "volsize", prop_type_number, 0, NULL, prop_default,
- ZFS_TYPE_VOLUME, "<size>", "VOLSIZE", B_TRUE, B_TRUE,
- ZFS_DELEG_PERM_VOLSIZE },
- { "volblocksize", prop_type_number, 8192, NULL, prop_readonly,
- ZFS_TYPE_VOLUME, "512 to 128k, power of 2", "VOLBLOCK", B_TRUE,
- B_TRUE, ZFS_DELEG_PERM_NONE },
- { "recordsize", prop_type_number, SPA_MAXBLOCKSIZE, NULL,
- prop_inherit,
- ZFS_TYPE_FILESYSTEM,
- "512 to 128k, power of 2", "RECSIZE", B_TRUE, B_TRUE,
- ZFS_DELEG_PERM_RECORDSIZE },
- { "mountpoint", prop_type_string, 0, "/", prop_inherit,
- ZFS_TYPE_FILESYSTEM,
- "<path> | legacy | none", "MOUNTPOINT", B_FALSE, B_TRUE,
- ZFS_DELEG_PERM_MOUNTPOINT },
- { "sharenfs", prop_type_string, 0, "off", prop_inherit,
+ "on | off | fletcher2 | fletcher4 | sha256", "CHECKSUM",
+ checksum_table);
+ register_index(ZFS_PROP_COMPRESSION, "compression",
+ ZIO_COMPRESS_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+ "on | off | lzjb | gzip | gzip-[1-9]", "COMPRESS", compress_table);
+ register_index(ZFS_PROP_SNAPDIR, "snapdir", ZFS_SNAPDIR_HIDDEN,
+ ZFS_TYPE_FILESYSTEM, "hidden | visible", "SNAPDIR", snapdir_table);
+ register_index(ZFS_PROP_ACLMODE, "aclmode", ZFS_ACL_GROUPMASK,
+ ZFS_TYPE_FILESYSTEM, "discard | groupmask | passthrough", "ACLMODE",
+ acl_mode_table);
+ register_index(ZFS_PROP_ACLINHERIT, "aclinherit", ZFS_ACL_SECURE,
ZFS_TYPE_FILESYSTEM,
- "on | off | share(1M) options", "SHARENFS", B_FALSE, B_TRUE,
- ZFS_DELEG_PERM_SHARENFS },
- { "checksum", prop_type_index, ZIO_CHECKSUM_DEFAULT, "on",
- prop_inherit, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "on | off | fletcher2 | fletcher4 | sha256", "CHECKSUM", B_TRUE,
- B_TRUE, ZFS_DELEG_PERM_CHECKSUM },
- { "compression", prop_type_index, ZIO_COMPRESS_DEFAULT, "off",
- prop_inherit, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "on | off | lzjb | gzip | gzip-[1-9]", "COMPRESS", B_TRUE, B_TRUE,
- ZFS_DELEG_PERM_COMPRESSION },
- { "atime", prop_type_boolean, 1, NULL, prop_inherit,
- ZFS_TYPE_FILESYSTEM,
- "on | off", "ATIME", B_TRUE, B_TRUE, ZFS_DELEG_PERM_ATIME },
- { "devices", prop_type_boolean, 1, NULL, prop_inherit,
- ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
- "on | off", "DEVICES", B_TRUE, B_TRUE, ZFS_DELEG_PERM_DEVICES },
- { "exec", prop_type_boolean, 1, NULL, prop_inherit,
- ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
- "on | off", "EXEC", B_TRUE, B_TRUE, ZFS_DELEG_PERM_EXEC },
- { "setuid", prop_type_boolean, 1, NULL, prop_inherit,
- ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "SETUID",
- B_TRUE, B_TRUE, ZFS_DELEG_PERM_SETUID },
- { "readonly", prop_type_boolean, 0, NULL, prop_inherit,
+ "discard | noallow | secure | passthrough", "ACLINHERIT",
+ acl_inherit_table);
+ register_index(ZFS_PROP_COPIES, "copies", 1,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "on | off", "RDONLY", B_TRUE, B_TRUE, ZFS_DELEG_PERM_READONLY },
- { "zoned", prop_type_boolean, 0, NULL, prop_inherit,
- ZFS_TYPE_FILESYSTEM,
- "on | off", "ZONED", B_TRUE, B_TRUE, ZFS_DELEG_PERM_ZONED },
- { "snapdir", prop_type_index, ZFS_SNAPDIR_HIDDEN, "hidden",
- prop_inherit,
- ZFS_TYPE_FILESYSTEM,
- "hidden | visible", "SNAPDIR", B_TRUE, B_TRUE,
- ZFS_DELEG_PERM_SNAPDIR },
- { "aclmode", prop_type_index, ZFS_ACL_GROUPMASK, "groupmask",
- prop_inherit, ZFS_TYPE_FILESYSTEM,
- "discard | groupmask | passthrough", "ACLMODE", B_TRUE,
- B_TRUE, ZFS_DELEG_PERM_ACLMODE },
- { "aclinherit", prop_type_index, ZFS_ACL_SECURE, "secure",
- prop_inherit, ZFS_TYPE_FILESYSTEM,
- "discard | noallow | secure | passthrough", "ACLINHERIT", B_TRUE,
- B_TRUE, ZFS_DELEG_PERM_ACLINHERIT },
- { "createtxg", prop_type_number, 0, NULL, prop_readonly,
- ZFS_TYPE_ANY, NULL, NULL, B_FALSE, B_FALSE, ZFS_DELEG_PERM_NONE },
- { "name", prop_type_string, 0, NULL, prop_readonly,
- ZFS_TYPE_ANY, NULL, "NAME", B_FALSE, B_FALSE, ZFS_DELEG_PERM_NONE },
- { "canmount", prop_type_boolean, 1, NULL, prop_default,
- ZFS_TYPE_FILESYSTEM,
- "on | off", "CANMOUNT", B_TRUE, B_TRUE, ZFS_DELEG_PERM_CANMOUNT },
- { "shareiscsi", prop_type_string, 0, "off", prop_inherit,
- ZFS_TYPE_ANY,
- "on | off | type=<type>", "SHAREISCSI", B_FALSE, B_TRUE,
- ZFS_DELEG_PERM_SHAREISCSI },
- { "iscsioptions", prop_type_string, 0, NULL, prop_inherit,
- ZFS_TYPE_VOLUME, NULL, "ISCSIOPTIONS", B_FALSE, B_FALSE,
- ZFS_DELEG_PERM_NONE },
- { "xattr", prop_type_boolean, 1, NULL, prop_inherit,
+ "1 | 2 | 3", "COPIES", copies_table);
+ register_index(ZFS_PROP_VERSION, "version", 0,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
- "on | off", "XATTR", B_TRUE, B_TRUE, ZFS_DELEG_PERM_XATTR },
- { "numclones", prop_type_number, 0, NULL, prop_readonly,
- ZFS_TYPE_SNAPSHOT, NULL, NULL, B_FALSE, B_FALSE,
- ZFS_DELEG_PERM_NONE },
- { "copies", prop_type_index, 1, "1", prop_inherit,
+ "1 | 2 | current", "VERSION", version_table);
+
+ /* string properties */
+ register_string(ZFS_PROP_ORIGIN, "origin", NULL, PROP_READONLY,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<snapshot>", "ORIGIN");
+ register_string(ZPOOL_PROP_BOOTFS, "bootfs", NULL, PROP_DEFAULT,
+ ZFS_TYPE_POOL, "<filesystem>", "BOOTFS");
+ register_string(ZFS_PROP_MOUNTPOINT, "mountpoint", "/", PROP_INHERIT,
+ ZFS_TYPE_FILESYSTEM, "<path> | legacy | none", "MOUNTPOINT");
+ register_string(ZFS_PROP_SHARENFS, "sharenfs", "off", PROP_INHERIT,
+ ZFS_TYPE_FILESYSTEM, "on | off | share(1M) options", "SHARENFS");
+ register_string(ZFS_PROP_SHAREISCSI, "shareiscsi", "off", PROP_INHERIT,
+ ZFS_TYPE_ANY, "on | off | type=<type>", "SHAREISCSI");
+ register_string(ZFS_PROP_TYPE, "type", NULL, PROP_READONLY,
+ ZFS_TYPE_ANY, "filesystem | volume | snapshot", "TYPE");
+
+ /* readonly number properties */
+ register_number(ZFS_PROP_USED, "used", 0, PROP_READONLY,
+ ZFS_TYPE_ANY, "<size>", "USED");
+ register_number(ZFS_PROP_AVAILABLE, "available", 0, PROP_READONLY,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
- "1 | 2 | 3", "COPIES", B_TRUE, B_TRUE, ZFS_DELEG_PERM_COPIES },
- { "bootfs", prop_type_string, 0, NULL, prop_default,
- ZFS_TYPE_POOL, "<filesystem>", "BOOTFS", B_FALSE,
- B_TRUE, ZFS_DELEG_PERM_NONE },
- { "autoreplace", prop_type_boolean, 0, NULL, prop_default,
- ZFS_TYPE_POOL, "on | off", "REPLACE", B_FALSE, B_TRUE,
- ZFS_DELEG_PERM_NONE },
- { "delegation", prop_type_boolean, 1, NULL, prop_default,
- ZFS_TYPE_POOL, "on | off", "DELEGATION", B_TRUE,
- B_TRUE, ZFS_DELEG_PERM_NONE },
- { "version", prop_type_index, 0, NULL, prop_default,
- ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "1 | 2 | current",
- "VERSION", B_TRUE, B_TRUE, ZFS_DELEG_PERM_VERSION },
-};
-
-#define ZFS_PROP_COUNT ((sizeof (zfs_prop_table))/(sizeof (prop_desc_t)))
+ "<size>", "AVAIL");
+ register_number(ZFS_PROP_REFERENCED, "referenced", 0, PROP_READONLY,
+ ZFS_TYPE_ANY, "<size>", "REFER");
+ register_number(ZFS_PROP_COMPRESSRATIO, "compressratio", 0,
+ PROP_READONLY, ZFS_TYPE_ANY,
+ "<1.00x or higher if compressed>", "RATIO");
+ register_number(ZFS_PROP_VOLBLOCKSIZE, "volblocksize", 8192,
+ PROP_READONLY,
+ ZFS_TYPE_VOLUME, "512 to 128k, power of 2", "VOLBLOCK");
+
+ /* default number properties */
+ register_number(ZFS_PROP_QUOTA, "quota", 0, PROP_DEFAULT,
+ ZFS_TYPE_FILESYSTEM, "<size> | none", "QUOTA");
+ register_number(ZFS_PROP_RESERVATION, "reservation", 0, PROP_DEFAULT,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size> | none", "RESERV");
+ register_number(ZFS_PROP_VOLSIZE, "volsize", 0, PROP_DEFAULT,
+ ZFS_TYPE_VOLUME, "<size>", "VOLSIZE");
+
+ /* inherit number properties */
+ register_number(ZFS_PROP_RECORDSIZE, "recordsize", SPA_MAXBLOCKSIZE,
+ PROP_INHERIT,
+ ZFS_TYPE_FILESYSTEM, "512 to 128k, power of 2", "RECSIZE");
+
+ /* readonly boolean properties */
+ register_boolean(ZFS_PROP_MOUNTED, "mounted", 0, PROP_READONLY,
+ ZFS_TYPE_FILESYSTEM, "yes | no | -", "MOUNTED");
+
+ /* default boolean properties */
+ register_boolean(ZFS_PROP_CANMOUNT, "canmount", 1, PROP_DEFAULT,
+ ZFS_TYPE_FILESYSTEM, "on | off", "CANMOUNT");
+ register_boolean(ZPOOL_PROP_DELEGATION, "delegation", 1, PROP_DEFAULT,
+ ZFS_TYPE_POOL, "on | off", "DELEGATION");
+ register_boolean(ZPOOL_PROP_AUTOREPLACE, "autoreplace", 0, PROP_DEFAULT,
+ ZFS_TYPE_POOL, "on | off", "REPLACE");
+
+ /* inherit boolean properties */
+ register_boolean(ZFS_PROP_ATIME, "atime", 1, PROP_INHERIT,
+ ZFS_TYPE_FILESYSTEM, "on | off", "ATIME");
+ register_boolean(ZFS_PROP_DEVICES, "devices", 1, PROP_INHERIT,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "DEVICES");
+ register_boolean(ZFS_PROP_EXEC, "exec", 1, PROP_INHERIT,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "EXEC");
+ register_boolean(ZFS_PROP_SETUID, "setuid", 1, PROP_INHERIT,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "SETUID");
+ register_boolean(ZFS_PROP_READONLY, "readonly", 0, PROP_INHERIT,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "on | off", "RDONLY");
+ register_boolean(ZFS_PROP_ZONED, "zoned", 0, PROP_INHERIT,
+ ZFS_TYPE_FILESYSTEM, "on | off", "ZONED");
+ register_boolean(ZFS_PROP_XATTR, "xattr", 1, PROP_INHERIT,
+ ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "XATTR");
+
+ /* hidden properties */
+ register_hidden(ZFS_PROP_CREATETXG, "createtxg", PROP_TYPE_NUMBER,
+ PROP_READONLY, ZFS_TYPE_ANY, NULL);
+ register_hidden(ZFS_PROP_NUMCLONES, "numclones", PROP_TYPE_NUMBER,
+ PROP_READONLY, ZFS_TYPE_SNAPSHOT, NULL);
+ register_hidden(ZFS_PROP_NAME, "name", PROP_TYPE_STRING,
+ PROP_READONLY, ZFS_TYPE_ANY, "NAME");
+ register_hidden(ZFS_PROP_ISCSIOPTIONS, "iscsioptions", PROP_TYPE_STRING,
+ PROP_INHERIT, ZFS_TYPE_VOLUME, "ISCSIOPTIONS");
+ register_hidden(ZPOOL_PROP_NAME, "zpoolname", PROP_TYPE_STRING,
+ PROP_READONLY, ZFS_TYPE_POOL, NULL);
+
+ /* oddball properties */
+ register_impl(ZFS_PROP_CREATION, "creation", PROP_TYPE_NUMBER, 0, NULL,
+ PROP_READONLY, ZFS_TYPE_ANY,
+ "<date>", "CREATION", B_FALSE, B_TRUE, NULL);
+}
+
/*
- * Returns TRUE if the property applies to the given dataset types.
+ * Returns TRUE if the property applies to any of the given dataset types.
*/
int
zfs_prop_valid_for_type(zfs_prop_t prop, int types)
@@ -240,28 +342,21 @@ zfs_prop_is_visible(zfs_prop_t prop)
* zfs_prop_table[]
*/
static int
-zfs_prop_compare(const void *p1, const void *p2)
+zfs_prop_compare(const void *arg1, const void *arg2)
{
- int i, j;
- prop_attr_t iattr, jattr;
+ const zfs_prop_t *p1 = arg1;
+ const zfs_prop_t *p2 = arg2;
+ boolean_t p1ro, p2ro;
- i = *((int *)p1);
- j = *((int *)p2);
+ p1ro = (zfs_prop_table[*p1].pd_attr == PROP_READONLY);
+ p2ro = (zfs_prop_table[*p2].pd_attr == PROP_READONLY);
- iattr = zfs_prop_table[i].pd_attr;
- jattr = zfs_prop_table[j].pd_attr;
-
- /* first, sort by whether the property is readonly or not */
- if (iattr != prop_readonly &&
- jattr == prop_readonly)
- return (1);
- if (iattr == prop_readonly &&
- jattr != prop_readonly)
- return (-1);
+ if (p1ro == p2ro) {
+ return (strcmp(zfs_prop_table[*p1].pd_name,
+ zfs_prop_table[*p2].pd_name));
+ }
- /* otherwise, sort by the property name */
- return (strcmp(zfs_prop_table[i].pd_name,
- zfs_prop_table[j].pd_name));
+ return (p1ro ? -1 : 1);
}
/*
@@ -275,19 +370,18 @@ zfs_prop_iter_common(zfs_prop_f func, void *cb, zfs_type_t type,
boolean_t show_all, boolean_t ordered)
{
int i;
- int order[ZFS_PROP_COUNT];
+ zfs_prop_t order[ZFS_NUM_PROPS];
- for (int j = 0; j < ZFS_PROP_COUNT; j++) {
+ for (int j = 0; j < ZFS_NUM_PROPS; j++)
order[j] = j;
- }
if (ordered) {
- qsort((void *)order, ZFS_PROP_COUNT, sizeof (zfs_prop_t),
+ qsort((void *)order, ZFS_NUM_PROPS, sizeof (zfs_prop_t),
zfs_prop_compare);
}
- for (i = 0; i < ZFS_PROP_COUNT; i++) {
+ for (i = 0; i < ZFS_NUM_PROPS; i++) {
if (zfs_prop_valid_for_type(order[i], type) &&
(zfs_prop_is_visible(order[i]) || show_all)) {
if (func(order[i], cb) != ZFS_PROP_CONT)
@@ -298,23 +392,21 @@ zfs_prop_iter_common(zfs_prop_f func, void *cb, zfs_type_t type,
}
zfs_prop_t
-zfs_prop_iter(zfs_prop_f func, void *cb, boolean_t show_all)
+zfs_prop_iter(zfs_prop_f func, void *cb)
{
- return (zfs_prop_iter_common(func, cb, ZFS_TYPE_ANY, show_all,
- B_FALSE));
+ return (zfs_prop_iter_common(func, cb, ZFS_TYPE_ANY, B_FALSE, B_FALSE));
}
zfs_prop_t
-zfs_prop_iter_ordered(zfs_prop_f func, void *cb, boolean_t show_all)
+zfs_prop_iter_ordered(zfs_prop_f func, void *cb)
{
- return (zfs_prop_iter_common(func, cb, ZFS_TYPE_ANY, show_all,
- B_TRUE));
+ return (zfs_prop_iter_common(func, cb, ZFS_TYPE_ANY, B_FALSE, B_TRUE));
}
zpool_prop_t
-zpool_prop_iter(zpool_prop_f func, void *cb, boolean_t show_all)
+zpool_prop_iter(zpool_prop_f func, void *cb)
{
- return (zfs_prop_iter_common(func, cb, ZFS_TYPE_POOL, show_all,
+ return (zfs_prop_iter_common(func, cb, ZFS_TYPE_POOL, B_FALSE,
B_FALSE));
}
@@ -337,9 +429,7 @@ propname_match(const char *p, zfs_prop_t prop, size_t len)
#ifndef _KERNEL
const char *colname = zfs_prop_table[prop].pd_colname;
int c;
-#endif
-#ifndef _KERNEL
if (colname == NULL)
return (B_FALSE);
#endif
@@ -367,9 +457,8 @@ zfs_name_to_prop_cb(zfs_prop_t prop, void *cb_data)
{
const char *propname = cb_data;
- if (propname_match(propname, prop, strlen(propname))) {
+ if (propname_match(propname, prop, strlen(propname)))
return (prop);
- }
return (ZFS_PROP_CONT);
}
@@ -405,10 +494,11 @@ zpool_name_to_prop(const char *propname)
return (zfs_name_to_prop_common(propname, ZFS_TYPE_POOL));
}
-const char *
-zfs_prop_perm(zfs_prop_t prop)
+boolean_t
+zfs_prop_delegatable(zfs_prop_t prop)
{
- return (zfs_prop_table[prop].pd_perm);
+ prop_desc_t *pd = &zfs_prop_table[prop];
+ return (pd->pd_attr != PROP_READONLY && pd->pd_types != ZFS_TYPE_POOL);
}
/*
@@ -480,7 +570,7 @@ zpool_prop_default_numeric(zpool_prop_t prop)
int
zfs_prop_readonly(zfs_prop_t prop)
{
- return (zfs_prop_table[prop].pd_attr == prop_readonly);
+ return (zfs_prop_table[prop].pd_attr == PROP_READONLY);
}
/*
@@ -509,96 +599,7 @@ zpool_prop_to_name(zpool_prop_t prop)
int
zfs_prop_inheritable(zfs_prop_t prop)
{
- return (zfs_prop_table[prop].pd_attr == prop_inherit);
-}
-
-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 },
- { "gzip", ZIO_COMPRESS_GZIP_6 }, /* the default gzip level */
- { "gzip-1", ZIO_COMPRESS_GZIP_1 },
- { "gzip-2", ZIO_COMPRESS_GZIP_2 },
- { "gzip-3", ZIO_COMPRESS_GZIP_3 },
- { "gzip-4", ZIO_COMPRESS_GZIP_4 },
- { "gzip-5", ZIO_COMPRESS_GZIP_5 },
- { "gzip-6", ZIO_COMPRESS_GZIP_6 },
- { "gzip-7", ZIO_COMPRESS_GZIP_7 },
- { "gzip-8", ZIO_COMPRESS_GZIP_8 },
- { "gzip-9", ZIO_COMPRESS_GZIP_9 },
- { 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 copies_table[] = {
- { "1", 1 },
- { "2", 2 },
- { "3", 3 },
- { NULL }
-};
-
-static zfs_index_t version_table[] = {
- { "1", 1 },
- { "2", 2 },
- { "current", ZPL_VERSION },
- { NULL }
-};
-
-static zfs_index_t *
-zfs_prop_index_table(zfs_prop_t prop)
-{
- switch (prop) {
- case ZFS_PROP_CHECKSUM:
- return (checksum_table);
- case ZFS_PROP_COMPRESSION:
- return (compress_table);
- case ZFS_PROP_SNAPDIR:
- return (snapdir_table);
- case ZFS_PROP_ACLMODE:
- return (acl_mode_table);
- case ZFS_PROP_ACLINHERIT:
- return (acl_inherit_table);
- case ZFS_PROP_COPIES:
- return (copies_table);
- case ZFS_PROP_VERSION:
- return (version_table);
- default:
- return (NULL);
- }
+ return (zfs_prop_table[prop].pd_attr == PROP_INHERIT);
}
/*
@@ -608,10 +609,10 @@ zfs_prop_index_table(zfs_prop_t prop)
int
zfs_prop_string_to_index(zfs_prop_t prop, const char *string, uint64_t *index)
{
- zfs_index_t *table;
+ const zfs_index_t *table;
int i;
- if ((table = zfs_prop_index_table(prop)) == NULL)
+ if ((table = zfs_prop_table[prop].pd_table) == NULL)
return (-1);
for (i = 0; table[i].name != NULL; i++) {
@@ -627,10 +628,10 @@ zfs_prop_string_to_index(zfs_prop_t prop, const char *string, uint64_t *index)
int
zfs_prop_index_to_string(zfs_prop_t prop, uint64_t index, const char **string)
{
- zfs_index_t *table;
+ const zfs_index_t *table;
int i;
- if ((table = zfs_prop_index_table(prop)) == NULL)
+ if ((table = zfs_prop_table[prop].pd_table) == NULL)
return (-1);
for (i = 0; table[i].name != NULL; i++) {
@@ -679,8 +680,8 @@ zpool_prop_values(zfs_prop_t prop)
int
zfs_prop_is_string(zfs_prop_t prop)
{
- return (zfs_prop_table[prop].pd_proptype == prop_type_string ||
- zfs_prop_table[prop].pd_proptype == prop_type_index);
+ return (zfs_prop_table[prop].pd_proptype == PROP_TYPE_STRING ||
+ zfs_prop_table[prop].pd_proptype == PROP_TYPE_INDEX);
}
/*
@@ -711,7 +712,7 @@ size_t
zfs_prop_width(zfs_prop_t prop, boolean_t *fixed)
{
prop_desc_t *pd = &zfs_prop_table[prop];
- zfs_index_t *idx;
+ const zfs_index_t *idx;
size_t ret;
int i;
@@ -727,7 +728,7 @@ zfs_prop_width(zfs_prop_t prop, boolean_t *fixed)
* any possible value.
*/
switch (pd->pd_proptype) {
- case prop_type_number:
+ case PROP_TYPE_NUMBER:
/*
* The maximum length of a human-readable number is 5 characters
* ("20.4M", for example).
@@ -741,7 +742,7 @@ zfs_prop_width(zfs_prop_t prop, boolean_t *fixed)
if (prop == ZFS_PROP_CREATION)
*fixed = B_FALSE;
break;
- case prop_type_boolean:
+ case PROP_TYPE_BOOLEAN:
/*
* The maximum length of a boolean value is 3 characters, for
* "off".
@@ -749,15 +750,15 @@ zfs_prop_width(zfs_prop_t prop, boolean_t *fixed)
if (ret < 3)
ret = 3;
break;
- case prop_type_index:
- idx = zfs_prop_index_table(prop);
+ case PROP_TYPE_INDEX:
+ idx = zfs_prop_table[prop].pd_table;
for (i = 0; idx[i].name != NULL; i++) {
if (strlen(idx[i].name) > ret)
ret = strlen(idx[i].name);
}
break;
- case prop_type_string:
+ case PROP_TYPE_STRING:
*fixed = B_FALSE;
break;
}
diff --git a/usr/src/common/zfs/zfs_prop.h b/usr/src/common/zfs/zfs_prop.h
index 3b18ec561f..a0cc65534d 100644
--- a/usr/src/common/zfs/zfs_prop.h
+++ b/usr/src/common/zfs/zfs_prop.h
@@ -40,15 +40,17 @@ extern "C" {
* in the kernel, but the string value in userland.
*/
typedef enum {
- prop_type_number, /* numeric value */
- prop_type_string, /* string value */
- prop_type_boolean, /* boolean value */
- prop_type_index /* numeric value indexed by string */
+ PROP_TYPE_NUMBER, /* numeric value */
+ PROP_TYPE_STRING, /* string value */
+ PROP_TYPE_BOOLEAN, /* boolean value */
+ PROP_TYPE_INDEX /* numeric value indexed by string */
} zfs_proptype_t;
zfs_proptype_t zfs_prop_get_type(zfs_prop_t);
zfs_proptype_t zpool_prop_get_type(zpool_prop_t);
size_t zfs_prop_width(zfs_prop_t, boolean_t *);
+boolean_t zfs_prop_delegatable(zfs_prop_t prop);
+void zfs_prop_init(void);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
index c7c2726fa6..c444062fa1 100644
--- a/usr/src/lib/libzfs/common/libzfs.h
+++ b/usr/src/lib/libzfs/common/libzfs.h
@@ -107,7 +107,6 @@ enum {
EZFS_BADWHO, /* invalid permission who */
EZFS_BADPERM, /* invalid permission */
EZFS_BADPERMSET, /* invalid permission set name */
- EZFS_PERMSET_CIRCULAR, /* circular dependency on permset */
EZFS_NODELEGATION, /* delegated administration is disabled */
EZFS_PERMRDONLY, /* pemissions are readonly */
EZFS_UNKNOWN
diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c
index 383b63169e..05c074437c 100644
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c
@@ -839,14 +839,14 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, char *pool_name,
*/
strval = NULL;
switch (zfs_prop_get_type(prop)) {
- case prop_type_boolean:
+ 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:
+ case PROP_TYPE_STRING:
if (nvpair_type(elem) != DATA_TYPE_STRING) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"'%s' must be a string"),
@@ -863,14 +863,14 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, char *pool_name,
}
break;
- case prop_type_number:
+ case PROP_TYPE_NUMBER:
if (prop_parse_number(hdl, elem, prop, &intval) != 0) {
(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
goto error;
}
break;
- case prop_type_index:
+ case PROP_TYPE_INDEX:
if (prop_parse_index(hdl, elem, prop, &intval) != 0) {
(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
goto error;
@@ -1312,21 +1312,12 @@ zfs_build_perms(zfs_handle_t *zhp, char *whostr, char *perms,
nvlist_t *perms_nvp = NULL;
nvlist_t *sets_nvp = NULL;
char errbuf[1024];
- char *who_tok;
+ char *who_tok, *perm;
int error;
*nvp = NULL;
if (perms) {
- /* Make sure permission string doesn't have an '=' sign in it */
- if (strchr(perms, '=') != NULL) {
- (void) snprintf(errbuf, sizeof (errbuf),
- dgettext(TEXT_DOMAIN,
- "permissions can't contain equal sign : '%s'"),
- perms);
- return (zfs_error(zhp->zfs_hdl, EZFS_BADPERM, errbuf));
- }
-
if ((error = nvlist_alloc(&perms_nvp,
NV_UNIQUE_NAME, 0)) != 0) {
return (1);
@@ -1351,6 +1342,12 @@ zfs_build_perms(zfs_handle_t *zhp, char *whostr, char *perms,
char what;
if ((error = permset_namecheck(whostr, &why, &what)) != 0) {
+ nvlist_free(who_nvp);
+ if (perms_nvp)
+ nvlist_free(perms_nvp);
+ if (sets_nvp)
+ nvlist_free(sets_nvp);
+
switch (why) {
case NAME_ERR_NO_AT:
zfs_error_aux(zhp->zfs_hdl,
@@ -1368,74 +1365,28 @@ zfs_build_perms(zfs_handle_t *zhp, char *whostr, char *perms,
* The first nvlist perms_nvp will have normal permissions and the
* other sets_nvp will have only permssion set names in it.
*/
-
-
- while (perms && *perms != '\0') {
- char *value;
- char *perm_name;
- nvlist_t *update_nvp;
- int perm_num;
- char canonical_name[64];
- char *canonicalp = canonical_name;
-
-
- update_nvp = perms_nvp;
-
- perm_num = getsubopt(&perms, zfs_deleg_perm_tab, &value);
- if (perm_num == -1) {
- zfs_prop_t prop;
-
- prop = zfs_name_to_prop(value);
- if (prop != ZFS_PROP_INVAL) {
- (void) snprintf(canonical_name,
- sizeof (canonical_name), "%s",
- zfs_prop_to_name(prop));
- perm_num = getsubopt(&canonicalp,
- zfs_deleg_perm_tab, &value);
- }
- }
- if (perm_num != -1) {
- perm_name = zfs_deleg_perm_tab[perm_num];
- } else { /* check and see if permission is a named set */
- if (value[0] == '@') {
-
- /*
- * make sure permssion set isn't defined
- * in terms of itself. ie.
- * @set1 = create,destroy,@set1
- */
- if (who_type == ZFS_DELEG_NAMED_SET &&
- strcmp(value, whostr) == 0) {
- nvlist_free(who_nvp);
- nvlist_free(perms_nvp);
- if (sets_nvp)
- nvlist_free(sets_nvp);
- (void) snprintf(errbuf,
- sizeof (errbuf),
- dgettext(TEXT_DOMAIN,
- "Invalid permission %s"), value);
- return (zfs_error(zhp->zfs_hdl,
- EZFS_PERMSET_CIRCULAR, errbuf));
- }
- update_nvp = sets_nvp;
- perm_name = value;
- } else {
- nvlist_free(who_nvp);
- nvlist_free(perms_nvp);
- if (sets_nvp)
- nvlist_free(sets_nvp);
- return (zfs_error(zhp->zfs_hdl,
- EZFS_BADPERM, value));
- }
+ for (perm = strtok(perms, ","); perm; perm = strtok(NULL, ",")) {
+ const char *perm_canonical = zfs_deleg_canonicalize_perm(perm);
+
+ if (perm_canonical) {
+ verify(nvlist_add_boolean(perms_nvp,
+ perm_canonical) == 0);
+ } else if (perm[0] == '@') {
+ verify(nvlist_add_boolean(sets_nvp, perm) == 0);
+ } else {
+ nvlist_free(who_nvp);
+ nvlist_free(perms_nvp);
+ nvlist_free(sets_nvp);
+ return (zfs_error(zhp->zfs_hdl, EZFS_BADPERM, perm));
}
- verify(nvlist_add_boolean(update_nvp, perm_name) == 0);
}
if (whostr && who_type != ZFS_DELEG_CREATE) {
who_tok = strtok(whostr, ",");
if (who_tok == NULL) {
nvlist_free(who_nvp);
- nvlist_free(perms_nvp);
+ if (perms_nvp)
+ nvlist_free(perms_nvp);
if (sets_nvp)
nvlist_free(sets_nvp);
(void) snprintf(errbuf, sizeof (errbuf),
@@ -1455,7 +1406,8 @@ zfs_build_perms(zfs_handle_t *zhp, char *whostr, char *perms,
&who_id);
if (error) {
nvlist_free(who_nvp);
- nvlist_free(perms_nvp);
+ if (perms_nvp)
+ nvlist_free(perms_nvp);
if (sets_nvp)
nvlist_free(sets_nvp);
(void) snprintf(errbuf, sizeof (errbuf),
@@ -1468,7 +1420,6 @@ zfs_build_perms(zfs_handle_t *zhp, char *whostr, char *perms,
/*
* add entries for both local and descendent when required
*/
-
zfs_perms_add_who_nvlist(who_nvp, who_id, who_tok,
perms_nvp, sets_nvp, who_type, inherit);
@@ -2321,13 +2272,13 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src,
default:
switch (zfs_prop_get_type(prop)) {
- case prop_type_number:
- case prop_type_boolean:
- case prop_type_index:
+ case PROP_TYPE_NUMBER:
+ case PROP_TYPE_BOOLEAN:
+ case PROP_TYPE_INDEX:
*val = getprop_uint64(zhp, prop, source);
break;
- case prop_type_string:
+ case PROP_TYPE_STRING:
default:
zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
"cannot get non-numeric property"));
@@ -2536,7 +2487,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
default:
switch (zfs_prop_get_type(prop)) {
- case prop_type_number:
+ case PROP_TYPE_NUMBER:
if (get_numeric_property(zhp, prop, src,
&source, &val) != 0)
return (-1);
@@ -2547,12 +2498,12 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
zfs_nicenum(val, propbuf, proplen);
break;
- case prop_type_string:
+ case PROP_TYPE_STRING:
(void) strlcpy(propbuf,
getprop_string(zhp, prop, &source), proplen);
break;
- case prop_type_boolean:
+ case PROP_TYPE_BOOLEAN:
if (get_numeric_property(zhp, prop, src,
&source, &val) != 0)
return (-1);
@@ -2560,7 +2511,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
break;
- case prop_type_index:
+ case PROP_TYPE_INDEX:
val = getprop_uint64(zhp, prop, &source);
if (zfs_prop_index_to_string(prop, val,
&strval) != 0)
diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c
index 26c4422b82..7c45ef727e 100644
--- a/usr/src/lib/libzfs/common/libzfs_util.c
+++ b/usr/src/lib/libzfs/common/libzfs_util.c
@@ -44,6 +44,7 @@
#include <libzfs.h>
#include "libzfs_impl.h"
+#include "zfs_prop.h"
int
libzfs_errno(libzfs_handle_t *hdl)
@@ -186,9 +187,6 @@ libzfs_error_description(libzfs_handle_t *hdl)
return (dgettext(TEXT_DOMAIN, "invalid permission"));
case EZFS_BADPERMSET:
return (dgettext(TEXT_DOMAIN, "invalid permission set name"));
- case EZFS_PERMSET_CIRCULAR:
- return (dgettext(TEXT_DOMAIN,
- "Cannot define a permission set in terms of itself"));
case EZFS_NODELEGATION:
return (dgettext(TEXT_DOMAIN, "delegated administration is "
"disabled on pool"));
@@ -556,6 +554,8 @@ libzfs_init(void)
hdl->libzfs_sharetab = fopen("/etc/dfs/sharetab", "r");
+ zfs_prop_init();
+
return (hdl);
}
diff --git a/usr/src/lib/libzfs_jni/common/libzfs_jni_main.c b/usr/src/lib/libzfs_jni/common/libzfs_jni_main.c
index 04f46bd982..c7973e9979 100644
--- a/usr/src/lib/libzfs_jni/common/libzfs_jni_main.c
+++ b/usr/src/lib/libzfs_jni/common/libzfs_jni_main.c
@@ -176,14 +176,13 @@ Java_com_sun_zfs_common_model_SystemDataModel_getPool(JNIEnv *env,
/* Verify that object is Pool, not some other Dataset */
if (pool != NULL) {
- jclass class = (*env)->FindClass(
- env, ZFSJNI_PACKAGE_DATA "Pool");
+ jclass class = (*env)->FindClass(
+ env, ZFSJNI_PACKAGE_DATA "Pool");
- jboolean is_pool = (*env)->IsInstanceOf(env, pool, class);
+ jboolean is_pool = (*env)->IsInstanceOf(env, pool, class);
- if (is_pool != JNI_TRUE) {
- pool = NULL;
- }
+ if (is_pool != JNI_TRUE)
+ pool = NULL;
}
return (pool);
@@ -570,7 +569,7 @@ Java_com_sun_zfs_common_model_SystemDataModel_getValidPropertyNames(JNIEnv *env,
map_data.env = env;
map_data.type = mappings[i].type;
map_data.list = list;
- (void) zfs_prop_iter(mapping_cb, &map_data, B_FALSE);
+ (void) zfs_prop_iter(mapping_cb, &map_data);
break;
}
}
diff --git a/usr/src/lib/libzfs_jni/common/libzfs_jni_property.c b/usr/src/lib/libzfs_jni/common/libzfs_jni_property.c
index 0247e92469..95114aa9fb 100644
--- a/usr/src/lib/libzfs_jni/common/libzfs_jni_property.c
+++ b/usr/src/lib/libzfs_jni/common/libzfs_jni_property.c
@@ -172,21 +172,19 @@ create_BasicProperty(JNIEnv *env, zfs_handle_t *zhp, zfs_prop_t prop,
jobject propValue = NULL;
if (convert_str != NULL) {
- char propbuf[ZFS_MAXPROPLEN];
- int result = zfs_prop_get(zhp, prop, propbuf,
- sizeof (propbuf), &srctype, source, sizeof (source), 1);
+ char propbuf[ZFS_MAXPROPLEN];
+ int result = zfs_prop_get(zhp, prop, propbuf,
+ sizeof (propbuf), &srctype, source, sizeof (source), 1);
- if (result == 0) {
- propValue = convert_str(env, propbuf);
- }
+ if (result == 0)
+ propValue = convert_str(env, propbuf);
} else {
- uint64_t value;
- int result = zfs_prop_get_numeric(
- zhp, prop, &value, &srctype, source, sizeof (source));
+ uint64_t value;
+ int result = zfs_prop_get_numeric(
+ zhp, prop, &value, &srctype, source, sizeof (source));
- if (result == 0) {
- propValue = convert_uint64(env, value);
- }
+ if (result == 0)
+ propValue = convert_uint64(env, value);
}
if (propValue != NULL) {
@@ -267,21 +265,19 @@ create_ObjectProperty(JNIEnv *env, zfs_handle_t *zhp, zfs_prop_t prop,
jobject propValue = NULL;
if (convert_str != NULL) {
- char propbuf[ZFS_MAXPROPLEN];
- int result = zfs_prop_get(zhp, prop, propbuf,
- sizeof (propbuf), &srctype, source, sizeof (source), 1);
+ char propbuf[ZFS_MAXPROPLEN];
+ int result = zfs_prop_get(zhp, prop, propbuf,
+ sizeof (propbuf), &srctype, source, sizeof (source), 1);
- if (result == 0) {
- propValue = convert_str(env, propbuf);
- }
+ if (result == 0)
+ propValue = convert_str(env, propbuf);
} else {
- uint64_t value;
- int result = zfs_prop_get_numeric(
- zhp, prop, &value, &srctype, source, sizeof (source));
+ uint64_t value;
+ int result = zfs_prop_get_numeric(
+ zhp, prop, &value, &srctype, source, sizeof (source));
- if (result == 0) {
- propValue = convert_uint64(env, value);
- }
+ if (result == 0)
+ propValue = convert_uint64(env, value);
}
if (propValue != NULL) {
@@ -520,10 +516,12 @@ zjni_get_default_property(JNIEnv *env, zfs_prop_t prop)
for (i = 0; props_custom[i].prop != ZFS_PROP_INVAL; i++) {
if (prop == props_custom[i].prop) {
- return create_default_ObjectProperty(env,
- props_custom[i].prop, props_custom[i].convert_str,
- props_custom[i].convert_uint64,
- props_custom[i].propClass, props_custom[i].valueClass);
+ return create_default_ObjectProperty(env,
+ props_custom[i].prop,
+ props_custom[i].convert_str,
+ props_custom[i].convert_uint64,
+ props_custom[i].propClass,
+ props_custom[i].valueClass);
}
}
@@ -546,8 +544,7 @@ zjni_get_property_from_name(const char *name)
{
zfs_prop_t prop;
- prop = zfs_prop_iter(zjni_get_property_from_name_cb, (void *)name,
- B_FALSE);
+ prop = zfs_prop_iter(zjni_get_property_from_name_cb, (void *)name);
return (prop == ZFS_PROP_CONT ? ZFS_PROP_INVAL : prop);
}
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 958a0395e6..e9de4ceac8 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -940,6 +940,7 @@ ZFS_COMMON_OBJS += \
lzjb.o \
metaslab.o \
refcount.o \
+ rprwlock.o \
sha256.o \
spa.o \
spa_config.o \
diff --git a/usr/src/uts/common/fs/zfs/dmu_objset.c b/usr/src/uts/common/fs/zfs/dmu_objset.c
index 11fea14a91..864cffa615 100644
--- a/usr/src/uts/common/fs/zfs/dmu_objset.c
+++ b/usr/src/uts/common/fs/zfs/dmu_objset.c
@@ -149,9 +149,11 @@ int
dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
objset_impl_t **osip)
{
- objset_impl_t *winner, *osi;
+ objset_impl_t *osi;
int i, err, checksum;
+ ASSERT(ds == NULL || MUTEX_HELD(&ds->ds_opening_lock));
+
osi = kmem_zalloc(sizeof (objset_impl_t), KM_SLEEP);
osi->os.os = osi;
osi->os_dsl_dataset = ds;
@@ -245,12 +247,13 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
osi->os_meta_dnode = dnode_special_open(osi,
&osi->os_phys->os_meta_dnode, DMU_META_DNODE_OBJECT);
- if (ds != NULL) {
- winner = dsl_dataset_set_user_ptr(ds, osi, dmu_objset_evict);
- if (winner) {
- dmu_objset_evict(ds, osi);
- osi = winner;
- }
+ /*
+ * We should be the only thread trying to do this because we
+ * have ds_opening_lock
+ */
+ if (ds) {
+ VERIFY(NULL == dsl_dataset_set_user_ptr(ds, osi,
+ dmu_objset_evict));
}
*osip = osi;
@@ -274,6 +277,7 @@ dmu_objset_open(const char *name, dmu_objset_type_t type, int mode,
return (err);
}
+ mutex_enter(&ds->ds_opening_lock);
osi = dsl_dataset_get_user_ptr(ds);
if (osi == NULL) {
err = dmu_objset_open_impl(dsl_dataset_get_spa(ds),
@@ -284,6 +288,7 @@ dmu_objset_open(const char *name, dmu_objset_type_t type, int mode,
return (err);
}
}
+ mutex_exit(&ds->ds_opening_lock);
os->os = osi;
os->os_mode = mode;
@@ -304,7 +309,7 @@ dmu_objset_close(objset_t *os)
}
int
-dmu_objset_evict_dbufs(objset_t *os, int try)
+dmu_objset_evict_dbufs(objset_t *os, boolean_t try)
{
objset_impl_t *osi = os->os;
dnode_t *dn;
@@ -402,7 +407,11 @@ dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
dnode_t *mdn;
ASSERT(dmu_tx_is_syncing(tx));
+ if (ds)
+ mutex_enter(&ds->ds_opening_lock);
VERIFY(0 == dmu_objset_open_impl(spa, ds, bp, &osi));
+ if (ds)
+ mutex_exit(&ds->ds_opening_lock);
mdn = osi->os_meta_dnode;
dnode_allocate(mdn, DMU_OT_DNODE, 1 << DNODE_BLOCK_SHIFT,
@@ -802,9 +811,10 @@ dmu_objset_sync(objset_impl_t *os, zio_t *pio, dmu_tx_t *tx)
zb.zb_object = 0;
zb.zb_level = -1;
zb.zb_blkid = 0;
- if (BP_IS_OLDER(os->os_rootbp, tx->tx_txg))
+ if (BP_IS_OLDER(os->os_rootbp, tx->tx_txg)) {
dsl_dataset_block_kill(os->os_dsl_dataset,
os->os_rootbp, pio, tx);
+ }
zio = arc_write(pio, os->os_spa, os->os_md_checksum,
os->os_md_compress,
dmu_get_replication_level(os, &zb, DMU_OT_OBJSET),
diff --git a/usr/src/uts/common/fs/zfs/dnode_sync.c b/usr/src/uts/common/fs/zfs/dnode_sync.c
index 04758568be..135adcfde6 100644
--- a/usr/src/uts/common/fs/zfs/dnode_sync.c
+++ b/usr/src/uts/common/fs/zfs/dnode_sync.c
@@ -350,7 +350,7 @@ dnode_sync_free_range(dnode_t *dn, uint64_t blkid, uint64_t nblks, dmu_tx_t *tx)
* Try to kick all the dnodes dbufs out of the cache...
*/
int
-dnode_evict_dbufs(dnode_t *dn, int try)
+dnode_evict_dbufs(dnode_t *dn, boolean_t try)
{
int progress;
int pass = 0;
diff --git a/usr/src/uts/common/fs/zfs/dsl_dataset.c b/usr/src/uts/common/fs/zfs/dsl_dataset.c
index 59482ce0df..d18a721084 100644
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c
+++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c
@@ -218,7 +218,6 @@ static void
dsl_dataset_evict(dmu_buf_t *db, void *dsv)
{
dsl_dataset_t *ds = dsv;
- dsl_pool_t *dp = ds->ds_dir->dd_pool;
/* open_refcount == DS_REF_MAX when deleting */
ASSERT(ds->ds_open_refcount == 0 ||
@@ -226,7 +225,7 @@ dsl_dataset_evict(dmu_buf_t *db, void *dsv)
dprintf_ds(ds, "evicting %s\n", "");
- unique_remove(ds->ds_phys->ds_fsid_guid);
+ unique_remove(ds->ds_fsid_guid);
if (ds->ds_user_ptr != NULL)
ds->ds_user_evict_func(ds, ds->ds_user_ptr);
@@ -239,10 +238,10 @@ dsl_dataset_evict(dmu_buf_t *db, void *dsv)
bplist_close(&ds->ds_deadlist);
dsl_dir_close(ds->ds_dir, ds);
- if (list_link_active(&ds->ds_synced_link))
- list_remove(&dp->dp_synced_objsets, ds);
+ ASSERT(!list_link_active(&ds->ds_synced_link));
mutex_destroy(&ds->ds_lock);
+ mutex_destroy(&ds->ds_opening_lock);
mutex_destroy(&ds->ds_deadlist.bpl_lock);
kmem_free(ds, sizeof (dsl_dataset_t));
@@ -299,6 +298,7 @@ dsl_dataset_open_obj(dsl_pool_t *dp, uint64_t dsobj, const char *snapname,
ds->ds_phys = dbuf->db_data;
mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL);
+ mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&ds->ds_deadlist.bpl_lock, NULL, MUTEX_DEFAULT,
NULL);
@@ -314,6 +314,7 @@ dsl_dataset_open_obj(dsl_pool_t *dp, uint64_t dsobj, const char *snapname,
* just opened it.
*/
mutex_destroy(&ds->ds_lock);
+ mutex_destroy(&ds->ds_opening_lock);
mutex_destroy(&ds->ds_deadlist.bpl_lock);
kmem_free(ds, sizeof (dsl_dataset_t));
dmu_buf_rele(dbuf, tag);
@@ -364,6 +365,7 @@ dsl_dataset_open_obj(dsl_pool_t *dp, uint64_t dsobj, const char *snapname,
}
dsl_dir_close(ds->ds_dir, ds);
mutex_destroy(&ds->ds_lock);
+ mutex_destroy(&ds->ds_opening_lock);
mutex_destroy(&ds->ds_deadlist.bpl_lock);
kmem_free(ds, sizeof (dsl_dataset_t));
if (err) {
@@ -372,12 +374,8 @@ dsl_dataset_open_obj(dsl_pool_t *dp, uint64_t dsobj, const char *snapname,
}
ds = winner;
} else {
- uint64_t new =
+ ds->ds_fsid_guid =
unique_insert(ds->ds_phys->ds_fsid_guid);
- if (new != ds->ds_phys->ds_fsid_guid) {
- /* XXX it won't necessarily be synced... */
- ds->ds_phys->ds_fsid_guid = new;
- }
}
}
ASSERT3P(ds->ds_dbuf, ==, dbuf);
@@ -554,7 +552,6 @@ dsl_dataset_create_root(dsl_pool_t *dp, uint64_t *ddobjp, dmu_tx_t *tx)
dsphys = dbuf->db_data;
dsphys->ds_dir_obj = dd->dd_object;
dsphys->ds_fsid_guid = unique_create();
- unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */
(void) random_get_pseudo_bytes((void*)&dsphys->ds_guid,
sizeof (dsphys->ds_guid));
dsphys->ds_snapnames_zapobj =
@@ -603,7 +600,6 @@ dsl_dataset_create_sync(dsl_dir_t *pdd,
dsphys = dbuf->db_data;
dsphys->ds_dir_obj = dd->dd_object;
dsphys->ds_fsid_guid = unique_create();
- unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */
(void) random_get_pseudo_bytes((void*)&dsphys->ds_guid,
sizeof (dsphys->ds_guid));
dsphys->ds_snapnames_zapobj =
@@ -1390,7 +1386,6 @@ dsl_dataset_snapshot_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
dsphys = dbuf->db_data;
dsphys->ds_dir_obj = ds->ds_dir->dd_object;
dsphys->ds_fsid_guid = unique_create();
- unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */
(void) random_get_pseudo_bytes((void*)&dsphys->ds_guid,
sizeof (dsphys->ds_guid));
dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj;
@@ -1453,9 +1448,15 @@ dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
ASSERT(ds->ds_user_ptr != NULL);
ASSERT(ds->ds_phys->ds_next_snap_obj == 0);
+ /*
+ * in case we had to change ds_fsid_guid when we opened it,
+ * sync it out now.
+ */
+ dmu_buf_will_dirty(ds->ds_dbuf, tx);
+ ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid;
+
dsl_dir_dirty(ds->ds_dir, tx);
dmu_objset_sync(ds->ds_user_ptr, zio, tx);
- /* Unneeded? bplist_close(&ds->ds_deadlist); */
}
void
@@ -1511,7 +1512,7 @@ dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat)
uint64_t
dsl_dataset_fsid_guid(dsl_dataset_t *ds)
{
- return (ds->ds_phys->ds_fsid_guid);
+ return (ds->ds_fsid_guid);
}
void
diff --git a/usr/src/uts/common/fs/zfs/dsl_deleg.c b/usr/src/uts/common/fs/zfs/dsl_deleg.c
index e8fc0df28c..dc1b52925a 100644
--- a/usr/src/uts/common/fs/zfs/dsl_deleg.c
+++ b/usr/src/uts/common/fs/zfs/dsl_deleg.c
@@ -89,17 +89,16 @@
/*
* Validate that user is allowed to delegate specified permissions.
*
- * In order to delegate "create" you must have create"
+ * In order to delegate "create" you must have "create"
* and "allow".
*/
int
dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr)
{
nvpair_t *whopair = NULL;
- int error = 0;
+ int error;
- if ((error = dsl_deleg_access(ddname,
- ZFS_DELEG_PERM_ALLOW, cr)) != 0)
+ if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
return (error);
while (whopair = nvlist_next_nvpair(nvp, whopair)) {
@@ -114,12 +113,11 @@ dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr)
if (strcmp(perm, ZFS_DELEG_PERM_ALLOW) == 0)
return (EPERM);
- if ((error = dsl_deleg_access(ddname,
- perm, cr)) != 0)
+ if ((error = dsl_deleg_access(ddname, perm, cr)) != 0)
return (error);
}
}
- return (error);
+ return (0);
}
/*
@@ -132,25 +130,23 @@ dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr)
{
nvpair_t *whopair = NULL;
int error;
+ char idstr[32];
- if ((error = dsl_deleg_access(ddname,
- ZFS_DELEG_PERM_ALLOW, cr)) != 0)
+ if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
return (error);
+ (void) snprintf(idstr, sizeof (idstr), "%lld",
+ (longlong_t)crgetuid(cr));
+
while (whopair = nvlist_next_nvpair(nvp, whopair)) {
zfs_deleg_who_type_t type = nvpair_name(whopair)[0];
- char idstr[32];
if (type != ZFS_DELEG_USER &&
type != ZFS_DELEG_USER_SETS)
return (EPERM);
- (void) snprintf(idstr, sizeof (idstr), "%lld",
- (longlong_t)crgetuid(cr));
if (strcmp(idstr, &nvpair_name(whopair)[3]) != 0)
return (EPERM);
-
- continue;
}
return (0);
}
@@ -184,6 +180,7 @@ dsl_deleg_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
uint64_t jumpobj;
if (nvpair_value_nvlist(whopair, &perms) != 0) {
+ ASSERT(pa->p_unset);
if (zap_lookup(mos, zapobj, whokey, 8,
1, &jumpobj) == 0) {
(void) zap_remove(mos, zapobj, whokey, tx);
@@ -201,7 +198,7 @@ dsl_deleg_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
* If object doesn't exist and we are removing
* it, then just continue to next item in nvlist
*/
- if (pa->p_unset == 1)
+ if (pa->p_unset)
continue;
jumpobj = zap_create(mos, DMU_OT_DSL_PERMS,
DMU_OT_NONE, 0, tx);
@@ -359,8 +356,8 @@ dsl_deleg_get(const char *ddname, nvlist_t **nvp)
*/
typedef struct perm_set {
avl_node_t p_node;
- char p_setname[ZFS_MAX_DELEG_NAME];
boolean_t p_matched;
+ char p_setname[ZFS_MAX_DELEG_NAME];
} perm_set_t;
static int
@@ -408,7 +405,7 @@ dsl_check_access(objset_t *mos, uint64_t zapobj,
* check a specified user/group for a requested permission
*/
static int
-dsl_check_user_access(objset_t *os, uint64_t zapobj, const char *perm,
+dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm,
int checkflag, cred_t *cr)
{
const gid_t *gids;
@@ -418,19 +415,19 @@ dsl_check_user_access(objset_t *os, uint64_t zapobj, const char *perm,
/* check for user */
id = crgetuid(cr);
- if (dsl_check_access(os, zapobj,
+ if (dsl_check_access(mos, zapobj,
ZFS_DELEG_USER, checkflag, &id, perm) == 0)
return (0);
/* check for users primary group */
id = crgetgid(cr);
- if (dsl_check_access(os, zapobj,
+ if (dsl_check_access(mos, zapobj,
ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
return (0);
/* check for everyone entry */
id = -1;
- if (dsl_check_access(os, zapobj,
+ if (dsl_check_access(mos, zapobj,
ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0)
return (0);
@@ -439,7 +436,7 @@ dsl_check_user_access(objset_t *os, uint64_t zapobj, const char *perm,
gids = crgetgroups(cr);
for (i = 0; i != ngids; i++) {
id = gids[i];
- if (dsl_check_access(os, zapobj,
+ if (dsl_check_access(mos, zapobj,
ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
return (0);
}
@@ -581,11 +578,6 @@ dsl_deleg_access(const char *ddname, const char *perm, cred_t *cr)
zfs_prop_to_name(ZFS_PROP_ZONED),
8, 1, &zoned, NULL) != 0)
break;
-
- /*
- * if zoned property isn't set then break
- * out and return EPERM.
- */
if (!zoned)
break;
}
@@ -595,12 +587,10 @@ dsl_deleg_access(const char *ddname, const char *perm, cred_t *cr)
continue;
dsl_load_user_sets(mos, zapobj, &permsets, checkflag, cr);
- setnode = avl_first(&permsets);
again:
expanded = B_FALSE;
for (setnode = avl_first(&permsets); setnode;
setnode = AVL_NEXT(&permsets, setnode)) {
-
if (setnode->p_matched == B_TRUE)
continue;
@@ -636,10 +626,8 @@ success:
dsl_dir_close(startdd, FTAG);
cookie = NULL;
- while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL) {
- /* These sets were used but never defined! */
+ while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL)
kmem_free(setnode, sizeof (perm_set_t));
- }
return (error);
}
@@ -649,12 +637,11 @@ success:
*/
static void
-copy_create_perms(objset_t *mos, uint64_t pzapobj, dsl_dir_t *dd,
+copy_create_perms(dsl_dir_t *dd, uint64_t pzapobj,
boolean_t dosets, uint64_t uid, dmu_tx_t *tx)
{
- int error;
+ objset_t *mos = dd->dd_pool->dp_meta_objset;
uint64_t jumpobj, pjumpobj;
- uint64_t zero = 0;
uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj;
zap_cursor_t zc;
zap_attribute_t za;
@@ -663,20 +650,18 @@ copy_create_perms(objset_t *mos, uint64_t pzapobj, dsl_dir_t *dd,
zfs_deleg_whokey(whokey,
dosets ? ZFS_DELEG_CREATE_SETS : ZFS_DELEG_CREATE,
ZFS_DELEG_LOCAL, NULL);
- error = zap_lookup(mos, pzapobj, whokey, 8, 1, &pjumpobj);
- if (error != 0)
+ if (zap_lookup(mos, pzapobj, whokey, 8, 1, &pjumpobj) != 0)
return;
- zfs_deleg_whokey(whokey,
- dosets ? ZFS_DELEG_USER_SETS : ZFS_DELEG_USER,
- ZFS_DELEG_LOCAL, &uid);
-
if (zapobj == 0) {
dmu_buf_will_dirty(dd->dd_dbuf, tx);
zapobj = dd->dd_phys->dd_deleg_zapobj = zap_create(mos,
DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
}
+ zfs_deleg_whokey(whokey,
+ dosets ? ZFS_DELEG_USER_SETS : ZFS_DELEG_USER,
+ ZFS_DELEG_LOCAL, &uid);
if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) == ENOENT) {
jumpobj = zap_create(mos, DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
VERIFY(zap_add(mos, zapobj, whokey, 8, 1, &jumpobj, tx) == 0);
@@ -685,6 +670,7 @@ copy_create_perms(objset_t *mos, uint64_t pzapobj, dsl_dir_t *dd,
for (zap_cursor_init(&zc, mos, pjumpobj);
zap_cursor_retrieve(&zc, &za) == 0;
zap_cursor_advance(&zc)) {
+ uint64_t zero = 0;
ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1);
VERIFY(zap_update(mos, jumpobj, za.za_name,
@@ -700,20 +686,20 @@ void
dsl_deleg_set_create_perms(dsl_dir_t *sdd, dmu_tx_t *tx, cred_t *cr)
{
dsl_dir_t *dd;
- objset_t *mos = sdd->dd_pool->dp_meta_objset;
+ uint64_t uid = crgetuid(cr);
if (spa_version(dmu_objset_spa(sdd->dd_pool->dp_meta_objset)) <
ZFS_VERSION_DELEGATED_PERMS)
return;
for (dd = sdd->dd_parent; dd != NULL; dd = dd->dd_parent) {
- uint64_t pobj = dd->dd_phys->dd_deleg_zapobj;
+ uint64_t pzapobj = dd->dd_phys->dd_deleg_zapobj;
- if (pobj == 0)
+ if (pzapobj == 0)
continue;
- copy_create_perms(mos, pobj, sdd, B_FALSE, crgetuid(cr), tx);
- copy_create_perms(mos, pobj, sdd, B_TRUE, crgetuid(cr), tx);
+ copy_create_perms(sdd, pzapobj, B_FALSE, uid, tx);
+ copy_create_perms(sdd, pzapobj, B_TRUE, uid, tx);
}
}
diff --git a/usr/src/uts/common/fs/zfs/dsl_prop.c b/usr/src/uts/common/fs/zfs/dsl_prop.c
index 103e80b8f6..e814fe27f3 100644
--- a/usr/src/uts/common/fs/zfs/dsl_prop.c
+++ b/usr/src/uts/common/fs/zfs/dsl_prop.c
@@ -48,7 +48,7 @@ dodefault(const char *propname, int intsz, int numint, void *buf)
zfs_prop_readonly(prop))
return (ENOENT);
- if (zfs_prop_get_type(prop) == prop_type_string) {
+ if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
if (intsz != 1)
return (EOVERFLOW);
(void) strncpy(buf, zfs_prop_default_string(prop), numint);
diff --git a/usr/src/uts/common/fs/zfs/refcount.c b/usr/src/uts/common/fs/zfs/refcount.c
index 411ed46e13..f1b3b23fe2 100644
--- a/usr/src/uts/common/fs/zfs/refcount.c
+++ b/usr/src/uts/common/fs/zfs/refcount.c
@@ -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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -61,11 +60,13 @@ refcount_fini(void)
void
refcount_create(refcount_t *rc)
{
+ mutex_init(&rc->rc_mtx, NULL, MUTEX_DEFAULT, NULL);
list_create(&rc->rc_list, sizeof (reference_t),
offsetof(reference_t, ref_link));
list_create(&rc->rc_removed, sizeof (reference_t),
offsetof(reference_t, ref_link));
- mutex_init(&rc->rc_mtx, NULL, MUTEX_DEFAULT, NULL);
+ rc->rc_count = 0;
+ rc->rc_removed_count = 0;
}
void
diff --git a/usr/src/uts/common/fs/zfs/rprwlock.c b/usr/src/uts/common/fs/zfs/rprwlock.c
new file mode 100644
index 0000000000..49ae505209
--- /dev/null
+++ b/usr/src/uts/common/fs/zfs/rprwlock.c
@@ -0,0 +1,118 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/zfs_context.h>
+#include <sys/refcount.h>
+#include <sys/rprwlock.h>
+
+void
+rprw_init(rprwlock_t *rwl)
+{
+ mutex_init(&rwl->rw_lock, NULL, MUTEX_DEFAULT, NULL);
+ rwl->rw_writer = NULL;
+ cv_init(&rwl->rw_cv, NULL, CV_DEFAULT, NULL);
+ refcount_create(&rwl->rw_count);
+}
+
+void
+rprw_destroy(rprwlock_t *rwl)
+{
+ mutex_destroy(&rwl->rw_lock);
+ ASSERT(rwl->rw_writer == NULL);
+ cv_destroy(&rwl->rw_cv);
+ refcount_destroy(&rwl->rw_count);
+}
+
+void
+rprw_enter_read(rprwlock_t *rwl, void *tag)
+{
+ mutex_enter(&rwl->rw_lock);
+
+ if (rwl->rw_writer != curthread) {
+ while (rwl->rw_writer != NULL)
+ cv_wait(&rwl->rw_cv, &rwl->rw_lock);
+ }
+
+ (void) refcount_add(&rwl->rw_count, tag);
+
+ mutex_exit(&rwl->rw_lock);
+}
+
+void
+rprw_enter_write(rprwlock_t *rwl, void *tag)
+{
+ mutex_enter(&rwl->rw_lock);
+
+ if (rwl->rw_writer != curthread) {
+ while (!refcount_is_zero(&rwl->rw_count))
+ cv_wait(&rwl->rw_cv, &rwl->rw_lock);
+ rwl->rw_writer = curthread;
+ }
+
+ (void) refcount_add(&rwl->rw_count, tag);
+
+ mutex_exit(&rwl->rw_lock);
+}
+
+void
+rprw_enter(rprwlock_t *rwl, krw_t rw, void *tag)
+{
+ if (rw == RW_READER)
+ rprw_enter_read(rwl, tag);
+ else
+ rprw_enter_write(rwl, tag);
+}
+
+void
+rprw_exit(rprwlock_t *rwl, void *tag)
+{
+ mutex_enter(&rwl->rw_lock);
+
+ ASSERT(!refcount_is_zero(&rwl->rw_count));
+ ASSERT(rwl->rw_writer == NULL || curthread == rwl->rw_writer);
+ if (refcount_remove(&rwl->rw_count, tag) == 0) {
+ cv_broadcast(&rwl->rw_cv);
+ rwl->rw_writer = NULL; /* OK in either case */
+ }
+
+ mutex_exit(&rwl->rw_lock);
+}
+
+boolean_t
+rprw_held(rprwlock_t *rwl, krw_t rw)
+{
+ boolean_t held;
+
+ mutex_enter(&rwl->rw_lock);
+ if (rw == RW_WRITER)
+ held = (rwl->rw_writer == curthread);
+ else
+ held = !rwl->rw_writer && !refcount_is_zero(&rwl->rw_count);
+ mutex_exit(&rwl->rw_lock);
+
+ return (held);
+}
diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c
index 6159e13aa0..e2435807a9 100644
--- a/usr/src/uts/common/fs/zfs/spa.c
+++ b/usr/src/uts/common/fs/zfs/spa.c
@@ -132,12 +132,13 @@ spa_activate(spa_t *spa)
rw_init(&spa->spa_traverse_lock, NULL, RW_DEFAULT, NULL);
+ rprw_init(&spa->spa_config_lock);
+
mutex_init(&spa->spa_async_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&spa->spa_config_cache_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&spa->spa_scrub_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&spa->spa_errlog_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&spa->spa_errlist_lock, NULL, MUTEX_DEFAULT, NULL);
- mutex_init(&spa->spa_config_lock.scl_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&spa->spa_sync_bplist.bpl_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&spa->spa_history_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&spa->spa_props_lock, NULL, MUTEX_DEFAULT, NULL);
diff --git a/usr/src/uts/common/fs/zfs/spa_config.c b/usr/src/uts/common/fs/zfs/spa_config.c
index 17a9b4cb9d..0ed306bc29 100644
--- a/usr/src/uts/common/fs/zfs/spa_config.c
+++ b/usr/src/uts/common/fs/zfs/spa_config.c
@@ -270,7 +270,8 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
vdev_t *rvd = spa->spa_root_vdev;
unsigned long hostid = 0;
- ASSERT(spa_config_held(spa, RW_READER));
+ ASSERT(spa_config_held(spa, RW_READER) ||
+ spa_config_held(spa, RW_WRITER));
if (vd == NULL)
vd = rvd;
diff --git a/usr/src/uts/common/fs/zfs/spa_misc.c b/usr/src/uts/common/fs/zfs/spa_misc.c
index 5035eb3d68..59bf92a552 100644
--- a/usr/src/uts/common/fs/zfs/spa_misc.c
+++ b/usr/src/uts/common/fs/zfs/spa_misc.c
@@ -45,6 +45,7 @@
#include <sys/dsl_prop.h>
#include <sys/fs/zfs.h>
#include <sys/metaslab_impl.h>
+#include "zfs_prop.h"
/*
* SPA locking
@@ -76,11 +77,10 @@
* some references in the DMU. Internally we check against SPA_MINREF, but
* present the image of a zero/non-zero value to consumers.
*
- * spa_config_lock (per-spa crazy rwlock)
+ * spa_config_lock (per-spa read-priority rwlock)
*
- * This SPA special is a recursive rwlock, capable of being acquired from
- * asynchronous threads. It has protects the spa_t from config changes,
- * and must be held in the following circumstances:
+ * This protects the spa_t from config changes, and must be held in
+ * the following circumstances:
*
* - RW_READER to perform I/O to the spa
* - RW_WRITER to change the vdev config
@@ -257,7 +257,7 @@ spa_add(const char *name, const char *altroot)
spa->spa_final_txg = UINT64_MAX;
refcount_create(&spa->spa_refcount);
- refcount_create(&spa->spa_config_lock.scl_count);
+ rprw_init(&spa->spa_config_lock);
avl_add(&spa_namespace_avl, spa);
@@ -298,10 +298,10 @@ spa_remove(spa_t *spa)
spa_config_set(spa, NULL);
refcount_destroy(&spa->spa_refcount);
- refcount_destroy(&spa->spa_config_lock.scl_count);
+
+ rprw_destroy(&spa->spa_config_lock);
mutex_destroy(&spa->spa_sync_bplist.bpl_lock);
- mutex_destroy(&spa->spa_config_lock.scl_lock);
mutex_destroy(&spa->spa_errlist_lock);
mutex_destroy(&spa->spa_errlog_lock);
mutex_destroy(&spa->spa_scrub_lock);
@@ -518,79 +518,22 @@ spa_spare_activate(vdev_t *vd)
* SPA config locking
* ==========================================================================
*/
-
-/*
- * Acquire the config lock. The config lock is a special rwlock that allows for
- * recursive enters. Because these enters come from the same thread as well as
- * asynchronous threads working on behalf of the owner, we must unilaterally
- * allow all reads access as long at least one reader is held (even if a write
- * is requested). This has the side effect of write starvation, but write locks
- * are extremely rare, and a solution to this problem would be significantly
- * more complex (if even possible).
- *
- * We would like to assert that the namespace lock isn't held, but this is a
- * valid use during create.
- */
void
spa_config_enter(spa_t *spa, krw_t rw, void *tag)
{
- spa_config_lock_t *scl = &spa->spa_config_lock;
-
- mutex_enter(&scl->scl_lock);
-
- if (scl->scl_writer != curthread) {
- if (rw == RW_READER) {
- while (scl->scl_writer != NULL)
- cv_wait(&scl->scl_cv, &scl->scl_lock);
- } else {
- while (scl->scl_writer != NULL ||
- !refcount_is_zero(&scl->scl_count))
- cv_wait(&scl->scl_cv, &scl->scl_lock);
- scl->scl_writer = curthread;
- }
- }
-
- (void) refcount_add(&scl->scl_count, tag);
-
- mutex_exit(&scl->scl_lock);
+ rprw_enter(&spa->spa_config_lock, rw, tag);
}
-/*
- * Release the spa config lock, notifying any waiters in the process.
- */
void
spa_config_exit(spa_t *spa, void *tag)
{
- spa_config_lock_t *scl = &spa->spa_config_lock;
-
- mutex_enter(&scl->scl_lock);
-
- ASSERT(!refcount_is_zero(&scl->scl_count));
- if (refcount_remove(&scl->scl_count, tag) == 0) {
- cv_broadcast(&scl->scl_cv);
- scl->scl_writer = NULL; /* OK in either case */
- }
-
- mutex_exit(&scl->scl_lock);
+ rprw_exit(&spa->spa_config_lock, tag);
}
-/*
- * Returns true if the config lock is held in the given manner.
- */
boolean_t
spa_config_held(spa_t *spa, krw_t rw)
{
- spa_config_lock_t *scl = &spa->spa_config_lock;
- boolean_t held;
-
- mutex_enter(&scl->scl_lock);
- if (rw == RW_WRITER)
- held = (scl->scl_writer == curthread);
- else
- held = !refcount_is_zero(&scl->scl_count);
- mutex_exit(&scl->scl_lock);
-
- return (held);
+ return (rprw_held(&spa->spa_config_lock, rw));
}
/*
@@ -1105,6 +1048,7 @@ spa_init(int mode)
zio_init();
dmu_init();
zil_init();
+ zfs_prop_init();
spa_config_load();
}
@@ -1116,6 +1060,7 @@ spa_fini(void)
zil_fini();
dmu_fini();
zio_fini();
+ unique_fini();
refcount_fini();
avl_destroy(&spa_namespace_avl);
diff --git a/usr/src/uts/common/fs/zfs/sys/dmu.h b/usr/src/uts/common/fs/zfs/sys/dmu.h
index eba1e64dc4..121152632d 100644
--- a/usr/src/uts/common/fs/zfs/sys/dmu.h
+++ b/usr/src/uts/common/fs/zfs/sys/dmu.h
@@ -157,7 +157,7 @@ void zfs_znode_byteswap(void *buf, size_t size);
int dmu_objset_open(const char *name, dmu_objset_type_t type, int mode,
objset_t **osp);
void dmu_objset_close(objset_t *os);
-int dmu_objset_evict_dbufs(objset_t *os, int try);
+int dmu_objset_evict_dbufs(objset_t *os, boolean_t try);
int dmu_objset_create(const char *name, dmu_objset_type_t type,
objset_t *clone_parent,
void (*func)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx), void *arg);
diff --git a/usr/src/uts/common/fs/zfs/sys/dmu_objset.h b/usr/src/uts/common/fs/zfs/sys/dmu_objset.h
index a401930af8..fbc1450b47 100644
--- a/usr/src/uts/common/fs/zfs/sys/dmu_objset.h
+++ b/usr/src/uts/common/fs/zfs/sys/dmu_objset.h
@@ -108,7 +108,7 @@ uint64_t dmu_objset_fsid_guid(objset_t *os);
int dmu_objset_find(char *name, int func(char *, void *), void *arg,
int flags);
void dmu_objset_byteswap(void *buf, size_t size);
-int dmu_objset_evict_dbufs(objset_t *os, int try);
+int dmu_objset_evict_dbufs(objset_t *os, boolean_t try);
/* called from dsl */
void dmu_objset_sync(objset_impl_t *os, zio_t *zio, dmu_tx_t *tx);
diff --git a/usr/src/uts/common/fs/zfs/sys/dnode.h b/usr/src/uts/common/fs/zfs/sys/dnode.h
index 327e538cf8..02f9de3f06 100644
--- a/usr/src/uts/common/fs/zfs/sys/dnode.h
+++ b/usr/src/uts/common/fs/zfs/sys/dnode.h
@@ -226,7 +226,7 @@ void dnode_init(void);
void dnode_fini(void);
int dnode_next_offset(dnode_t *dn, boolean_t hole, uint64_t *off, int minlvl,
uint64_t blkfill, uint64_t txg);
-int dnode_evict_dbufs(dnode_t *dn, int try);
+int dnode_evict_dbufs(dnode_t *dn, boolean_t try);
#ifdef ZFS_DEBUG
diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
index 8cfc1dcc98..2a8d354be4 100644
--- a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
+++ b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
@@ -87,6 +87,7 @@ typedef struct dsl_dataset {
dsl_dataset_phys_t *ds_phys;
dmu_buf_t *ds_dbuf;
uint64_t ds_object;
+ uint64_t ds_fsid_guid;
/* only used in syncing context: */
struct dsl_dataset *ds_prev; /* only valid for non-snapshots */
@@ -110,6 +111,9 @@ typedef struct dsl_dataset {
/* no locking; only for making guesses */
uint64_t ds_trysnap_txg;
+ /* for objset_open() */
+ kmutex_t ds_opening_lock;
+
/* Protected by ds_lock; keep at end of struct for better locality */
char ds_snapname[MAXNAMELEN];
} dsl_dataset_t;
diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h b/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h
index 1cc22b3dc8..1d01123c77 100644
--- a/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h
+++ b/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h
@@ -23,8 +23,8 @@
* Use is subject to license terms.
*/
-#ifndef _SYS_DSL_PERMS_H
-#define _SYS_DSL_PERMS_H
+#ifndef _SYS_DSL_DELEG_H
+#define _SYS_DSL_DELEG_H
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -48,30 +48,13 @@ extern "C" {
#define ZFS_DELEG_PERM_SHARE "share"
#define ZFS_DELEG_PERM_SEND "send"
#define ZFS_DELEG_PERM_RECEIVE "receive"
-#define ZFS_DELEG_PERM_QUOTA "quota"
-#define ZFS_DELEG_PERM_RESERVATION "reservation"
-#define ZFS_DELEG_PERM_VOLSIZE "volsize"
-#define ZFS_DELEG_PERM_RECORDSIZE "recordsize"
-#define ZFS_DELEG_PERM_MOUNTPOINT "mountpoint"
-#define ZFS_DELEG_PERM_SHARENFS "sharenfs"
-#define ZFS_DELEG_PERM_CHECKSUM "checksum"
-#define ZFS_DELEG_PERM_COMPRESSION "compression"
-#define ZFS_DELEG_PERM_ATIME "atime"
-#define ZFS_DELEG_PERM_DEVICES "devices"
-#define ZFS_DELEG_PERM_EXEC "exec"
-#define ZFS_DELEG_PERM_SETUID "setuid"
-#define ZFS_DELEG_PERM_READONLY "readonly"
-#define ZFS_DELEG_PERM_ZONED "zoned"
-#define ZFS_DELEG_PERM_SNAPDIR "snapdir"
-#define ZFS_DELEG_PERM_ACLMODE "aclmode"
-#define ZFS_DELEG_PERM_ACLINHERIT "aclinherit"
#define ZFS_DELEG_PERM_ALLOW "allow"
-#define ZFS_DELEG_PERM_CANMOUNT "canmount"
#define ZFS_DELEG_PERM_USERPROP "userprop"
-#define ZFS_DELEG_PERM_SHAREISCSI "shareiscsi"
-#define ZFS_DELEG_PERM_XATTR "xattr"
-#define ZFS_DELEG_PERM_COPIES "copies"
-#define ZFS_DELEG_PERM_VERSION "version"
+
+/*
+ * Note: the names of properties that are marked delegatable are also
+ * valid delegated permissions
+ */
int dsl_deleg_get(const char *ddname, nvlist_t **nvp);
int dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset);
@@ -80,10 +63,10 @@ void dsl_deleg_set_create_perms(dsl_dir_t *dd, dmu_tx_t *tx, cred_t *cr);
int dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr);
int dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr);
int dsl_deleg_destroy(objset_t *os, uint64_t zapobj, dmu_tx_t *tx);
-boolean_t dsl_delegation_on(objset_t *os);
+boolean_t dsl_delegation_on(objset_t *os);
#ifdef __cplusplus
}
#endif
-#endif /* _SYS_DSL_PERMS_H */
+#endif /* _SYS_DSL_DELEG_H */
diff --git a/usr/src/uts/common/fs/zfs/sys/refcount.h b/usr/src/uts/common/fs/zfs/sys/refcount.h
index 0b7e12f2cb..d3fe7b1f89 100644
--- a/usr/src/uts/common/fs/zfs/sys/refcount.h
+++ b/usr/src/uts/common/fs/zfs/sys/refcount.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -59,7 +59,7 @@ typedef struct refcount {
int64_t rc_removed_count;
} refcount_t;
-/* Note: refcount_t should be initialized to zero before use. */
+/* Note: refcount_t must be initialized with refcount_create() */
void refcount_create(refcount_t *rc);
void refcount_destroy(refcount_t *rc);
diff --git a/usr/src/uts/common/fs/zfs/sys/rprwlock.h b/usr/src/uts/common/fs/zfs/sys/rprwlock.h
new file mode 100644
index 0000000000..ba23799c9d
--- /dev/null
+++ b/usr/src/uts/common/fs/zfs/sys/rprwlock.h
@@ -0,0 +1,61 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_RPRWLOCK_H
+#define _SYS_RPRWLOCK_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/inttypes.h>
+#include <sys/list.h>
+#include <sys/zfs_context.h>
+#include <sys/refcount.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct rprwlock {
+ kmutex_t rw_lock;
+ kthread_t *rw_writer;
+ kcondvar_t rw_cv;
+ refcount_t rw_count;
+} rprwlock_t;
+
+void rprw_init(rprwlock_t *rwl);
+void rprw_destroy(rprwlock_t *rwl);
+void rprw_enter_read(rprwlock_t *rwl, void *tag);
+void rprw_enter_write(rprwlock_t *rwl, void *tag);
+void rprw_enter(rprwlock_t *rwl, krw_t rw, void *tag);
+void rprw_exit(rprwlock_t *rwl, void *tag);
+boolean_t rprw_held(rprwlock_t *rwl, krw_t rw);
+#define RPRW_READ_HELD(x) rprw_held(x, RW_READER)
+#define RPRW_WRITE_HELD(x) rprw_held(x, RW_WRITER)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_RPRWLOCK_H */
diff --git a/usr/src/uts/common/fs/zfs/sys/spa_impl.h b/usr/src/uts/common/fs/zfs/sys/spa_impl.h
index 0d155d7c0c..c313c696a4 100644
--- a/usr/src/uts/common/fs/zfs/sys/spa_impl.h
+++ b/usr/src/uts/common/fs/zfs/sys/spa_impl.h
@@ -37,19 +37,13 @@
#include <sys/zfs_context.h>
#include <sys/avl.h>
#include <sys/refcount.h>
+#include <sys/rprwlock.h>
#include <sys/bplist.h>
#ifdef __cplusplus
extern "C" {
#endif
-typedef struct spa_config_lock {
- kmutex_t scl_lock;
- refcount_t scl_count;
- kthread_t *scl_writer;
- kcondvar_t scl_cv;
-} spa_config_lock_t;
-
typedef struct spa_error_entry {
zbookmark_t se_bookmark;
char *se_name;
@@ -152,11 +146,12 @@ struct spa {
uint64_t spa_bootfs; /* default boot filesystem */
boolean_t spa_delegation; /* delegation on/off */
/*
- * spa_refcnt must be the last element because it changes size based on
- * compilation options. In order for the MDB module to function
- * correctly, the other fields must remain in the same location.
+ * spa_refcnt & spa_config_lock must be the last elements
+ * because refcount_t changes size based on compilation options.
+ * In order for the MDB module to function correctly, the other
+ * fields must remain in the same location.
*/
- spa_config_lock_t spa_config_lock; /* configuration changes */
+ rprwlock_t spa_config_lock; /* configuration changes */
refcount_t spa_refcount; /* number of opens */
};
diff --git a/usr/src/uts/common/fs/zfs/sys/unique.h b/usr/src/uts/common/fs/zfs/sys/unique.h
index c8c177e3ca..2ef3093edf 100644
--- a/usr/src/uts/common/fs/zfs/sys/unique.h
+++ b/usr/src/uts/common/fs/zfs/sys/unique.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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -39,8 +38,12 @@ extern "C" {
#define UNIQUE_BITS 56
void unique_init(void);
+void unique_fini(void);
-/* Return a new unique value. */
+/*
+ * Return a new unique value (which will not be uniquified against until
+ * it is unique_insert()-ed.
+ */
uint64_t unique_create(void);
/* Return a unique value, which equals the one passed in if possible. */
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 8228fe4709..663e8ac64b 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
@@ -133,8 +133,6 @@ typedef struct zfs_cmd {
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_objset_type;
uint64_t zc_perm_action;
uint64_t zc_history; /* really (char *) */
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h b/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h
index 7a9d578d6e..e76ccc3ce5 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h
@@ -52,10 +52,9 @@ struct zfsvfs {
uint_t z_acl_mode; /* acl chmod/mode behavior */
uint_t z_acl_inherit; /* acl inheritance behavior */
boolean_t z_atime; /* enable atimes mount option */
- boolean_t z_unmounted1; /* unmounted phase 1 */
- boolean_t z_unmounted2; /* unmounted phase 2 */
- uint32_t z_op_cnt; /* vnode/vfs operations ref count */
- krwlock_t z_um_lock; /* rw lock for umount phase 2 */
+ boolean_t z_unmounted; /* unmounted */
+ krwlock_t z_unmount_lock;
+ krwlock_t z_unmount_inactive_lock;
list_t z_all_znodes; /* all vnodes in the fs */
kmutex_t z_znodes_lock; /* lock for z_all_znodes */
vnode_t *z_ctldir; /* .zfs directory pointer */
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
index 4b731ba320..54f9c39619 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h
@@ -192,13 +192,15 @@ typedef struct znode {
*/
#define ZFS_ENTER(zfsvfs) \
{ \
- atomic_add_32(&(zfsvfs)->z_op_cnt, 1); \
- if ((zfsvfs)->z_unmounted1) { \
+ if (rw_tryenter(&(zfsvfs)->z_unmount_lock, RW_READER) == 0) \
+ return (EIO); \
+ if ((zfsvfs)->z_unmounted) { \
ZFS_EXIT(zfsvfs); \
return (EIO); \
} \
}
-#define ZFS_EXIT(zfsvfs) atomic_add_32(&(zfsvfs)->z_op_cnt, -1)
+
+#define ZFS_EXIT(zfsvfs) rw_exit(&(zfsvfs)->z_unmount_lock)
/*
* Macros for dealing with dmu_buf_hold
diff --git a/usr/src/uts/common/fs/zfs/sys/zvol.h b/usr/src/uts/common/fs/zfs/sys/zvol.h
index 34f1ca1c31..f7a0f8fd4e 100644
--- a/usr/src/uts/common/fs/zfs/sys/zvol.h
+++ b/usr/src/uts/common/fs/zfs/sys/zvol.h
@@ -40,9 +40,9 @@ 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, nvlist_t *nv);
extern void zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
-extern int zvol_create_minor(const char *, dev_t);
+extern int zvol_create_minor(const char *, major_t);
extern int zvol_remove_minor(const char *);
-extern int zvol_set_volsize(const char *, dev_t, uint64_t);
+extern int zvol_set_volsize(const char *, major_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);
diff --git a/usr/src/uts/common/fs/zfs/unique.c b/usr/src/uts/common/fs/zfs/unique.c
index 90aa13817d..fbe7b619a2 100644
--- a/usr/src/uts/common/fs/zfs/unique.c
+++ b/usr/src/uts/common/fs/zfs/unique.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,7 +30,7 @@
#include <sys/unique.h>
static avl_tree_t unique_avl;
-static kmutex_t unique_mtx; /* Lock never initialized. */
+static kmutex_t unique_mtx;
typedef struct unique {
avl_node_t un_link;
@@ -57,12 +57,22 @@ unique_init(void)
{
avl_create(&unique_avl, unique_compare,
sizeof (unique_t), offsetof(unique_t, un_link));
+ mutex_init(&unique_mtx, NULL, MUTEX_DEFAULT, NULL);
+}
+
+void
+unique_fini(void)
+{
+ avl_destroy(&unique_avl);
+ mutex_destroy(&unique_mtx);
}
uint64_t
unique_create(void)
{
- return (unique_insert(0));
+ uint64_t value = unique_insert(0);
+ unique_remove(value);
+ return (value);
}
uint64_t
diff --git a/usr/src/uts/common/fs/zfs/vdev_label.c b/usr/src/uts/common/fs/zfs/vdev_label.c
index 0158228a34..4b22a68fee 100644
--- a/usr/src/uts/common/fs/zfs/vdev_label.c
+++ b/usr/src/uts/common/fs/zfs/vdev_label.c
@@ -318,7 +318,8 @@ vdev_label_read_config(vdev_t *vd)
zio_t *zio;
int l;
- ASSERT(spa_config_held(spa, RW_READER));
+ ASSERT(spa_config_held(spa, RW_READER) ||
+ spa_config_held(spa, RW_WRITER));
if (vdev_is_dead(vd))
return (NULL);
diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
index 5947676818..2e95ae6c52 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
@@ -280,7 +280,7 @@ zfs_secpolicy_setprop(const char *name, zfs_prop_t prop, cred_t *cr)
break;
}
- return (zfs_secpolicy_write_perms(name, zfs_prop_perm(prop), cr));
+ return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr));
}
int
@@ -1175,7 +1175,7 @@ retry:
}
static int
-zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl)
+zfs_set_prop_nvlist(const char *name, nvlist_t *nvl)
{
nvpair_t *elem;
int error;
@@ -1200,13 +1200,13 @@ zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl)
return (EINVAL);
error = zfs_secpolicy_write_perms(name,
- ZFS_DELEG_PERM_USERPROP, cr);
+ ZFS_DELEG_PERM_USERPROP, CRED());
if (error)
return (error);
continue;
}
- if ((error = zfs_secpolicy_setprop(name, prop, cr)) != 0)
+ if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0)
return (error);
/*
@@ -1285,7 +1285,8 @@ zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl)
case ZFS_PROP_VOLSIZE:
if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
- (error = zvol_set_volsize(name, dev, intval)) != 0)
+ (error = zvol_set_volsize(name,
+ ddi_driver_major(zfs_dip), intval)) != 0)
return (error);
break;
@@ -1304,7 +1305,7 @@ zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl)
default:
if (nvpair_type(elem) == DATA_TYPE_STRING) {
if (zfs_prop_get_type(prop) !=
- prop_type_string)
+ PROP_TYPE_STRING)
return (EINVAL);
VERIFY(nvpair_value_string(elem, &strval) == 0);
if ((error = dsl_prop_set(name,
@@ -1317,15 +1318,15 @@ zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl)
VERIFY(nvpair_value_uint64(elem, &intval) == 0);
switch (zfs_prop_get_type(prop)) {
- case prop_type_number:
+ case PROP_TYPE_NUMBER:
break;
- case prop_type_boolean:
+ case PROP_TYPE_BOOLEAN:
if (intval > 1)
return (EINVAL);
break;
- case prop_type_string:
+ case PROP_TYPE_STRING:
return (EINVAL);
- case prop_type_index:
+ case PROP_TYPE_INDEX:
if (zfs_prop_index_to_string(prop,
intval, &unused) != 0)
return (EINVAL);
@@ -1366,13 +1367,12 @@ zfs_ioc_set_prop(zfs_cmd_t *zc)
if (!zfs_prop_user(zc->zc_value))
return (EINVAL);
error = zfs_secpolicy_write_perms(zc->zc_name,
- ZFS_DELEG_PERM_USERPROP,
- (cred_t *)(uintptr_t)zc->zc_cred);
+ ZFS_DELEG_PERM_USERPROP, CRED());
} else {
if (!zfs_prop_inheritable(prop))
return (EINVAL);
error = zfs_secpolicy_setprop(zc->zc_name,
- prop, (cred_t *)(uintptr_t)zc->zc_cred);
+ prop, CRED());
}
if (error)
return (error);
@@ -1383,8 +1383,7 @@ zfs_ioc_set_prop(zfs_cmd_t *zc)
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);
+ error = zfs_set_prop_nvlist(zc->zc_name, nvl);
nvlist_free(nvl);
return (error);
@@ -1555,7 +1554,7 @@ zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc)
}
nvlist_free(nvp);
error = dsl_deleg_access(zc->zc_name,
- ZFS_DELEG_PERM_SHAREISCSI, usercred);
+ zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred);
crfree(usercred);
return (error);
}
@@ -1565,7 +1564,6 @@ zfs_ioc_set_fsacl(zfs_cmd_t *zc)
{
int error;
nvlist_t *fsaclnv = NULL;
- cred_t *cr;
if ((error = get_nvlist(zc, &fsaclnv)) != 0)
return (error);
@@ -1584,13 +1582,15 @@ zfs_ioc_set_fsacl(zfs_cmd_t *zc)
* the nvlist(s)
*/
- cr = (cred_t *)(uintptr_t)zc->zc_cred;
- error = secpolicy_zfs(cr);
+ error = secpolicy_zfs(CRED());
if (error) {
- if (zc->zc_perm_action == B_FALSE)
- error = dsl_deleg_can_allow(zc->zc_name, fsaclnv, cr);
- else
- error = dsl_deleg_can_unallow(zc->zc_name, fsaclnv, cr);
+ if (zc->zc_perm_action == B_FALSE) {
+ error = dsl_deleg_can_allow(zc->zc_name,
+ fsaclnv, CRED());
+ } else {
+ error = dsl_deleg_can_unallow(zc->zc_name,
+ fsaclnv, CRED());
+ }
}
if (error == 0)
@@ -1617,7 +1617,7 @@ zfs_ioc_get_fsacl(zfs_cmd_t *zc)
static int
zfs_ioc_create_minor(zfs_cmd_t *zc)
{
- return (zvol_create_minor(zc->zc_name, zc->zc_dev));
+ return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip)));
}
static int
@@ -1766,9 +1766,7 @@ zfs_ioc_create(zfs_cmd_t *zc)
* 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,
- nvprops)) != 0)
+ if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0)
(void) dmu_objset_destroy(zc->zc_name);
}
@@ -2185,6 +2183,7 @@ zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp));
vec = cmd - ZFS_IOC;
+ ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip));
if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
return (EINVAL);
@@ -2193,11 +2192,8 @@ zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t));
- if (error == 0) {
- zc->zc_cred = (uintptr_t)cr;
- zc->zc_dev = dev;
+ if (error == 0)
error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr);
- }
/*
* Ensure that all pool/dataset names are valid before we pass down to
diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
index f69fdff1ce..c36dc9f23a 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
@@ -73,7 +73,6 @@ static int zfs_root(vfs_t *vfsp, vnode_t **vpp);
static int zfs_statvfs(vfs_t *vfsp, struct statvfs64 *statp);
static int zfs_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp);
static void zfs_freevfs(vfs_t *vfsp);
-static void zfs_objset_close(zfsvfs_t *zfsvfs);
static const fs_operation_def_t zfs_vfsops_template[] = {
VFSNAME_MOUNT, { .vfs_mount = zfs_mount },
@@ -526,7 +525,8 @@ zfs_domount(vfs_t *vfsp, char *osname, cred_t *cr)
mutex_init(&zfsvfs->z_znodes_lock, NULL, MUTEX_DEFAULT, NULL);
list_create(&zfsvfs->z_all_znodes, sizeof (znode_t),
offsetof(znode_t, z_link_node));
- rw_init(&zfsvfs->z_um_lock, NULL, RW_DEFAULT, NULL);
+ rw_init(&zfsvfs->z_unmount_lock, NULL, RW_DEFAULT, NULL);
+ rw_init(&zfsvfs->z_unmount_inactive_lock, NULL, RW_DEFAULT, NULL);
/* Initialize the generic filesystem structure. */
vfsp->vfs_bcount = 0;
@@ -1009,6 +1009,8 @@ static int
zfs_umount(vfs_t *vfsp, int fflag, cred_t *cr)
{
zfsvfs_t *zfsvfs = vfsp->vfs_data;
+ objset_t *os = zfsvfs->z_os;
+ znode_t *zp, *nextzp;
int ret;
ret = secpolicy_fs_unmount(cr, vfsp);
@@ -1036,58 +1038,102 @@ zfs_umount(vfs_t *vfsp, int fflag, cred_t *cr)
return (ret);
}
- if (fflag & MS_FORCE) {
- vfsp->vfs_flag |= VFS_UNMOUNTED;
- zfsvfs->z_unmounted1 = B_TRUE;
-
- /*
- * Ensure that z_unmounted1 reaches global visibility
- * before z_op_cnt.
- */
- membar_producer();
-
+ if (!(fflag & MS_FORCE)) {
/*
- * Wait for all zfs threads to leave zfs.
- * Grabbing a rwlock as reader in all vops and
- * as writer here doesn't work because it too easy to get
- * multiple reader enters as zfs can re-enter itself.
- * This can lead to deadlock if there is an intervening
- * rw_enter as writer.
- * So a file system threads ref count (z_op_cnt) is used.
- * A polling loop on z_op_cnt may seem inefficient, but
- * - this saves all threads on exit from having to grab a
- * mutex in order to cv_signal
- * - only occurs on forced unmount in the rare case when
- * there are outstanding threads within the file system.
+ * Check the number of active vnodes in the file system.
+ * Our count is maintained in the vfs structure, but the
+ * number is off by 1 to indicate a hold on the vfs
+ * structure itself.
+ *
+ * The '.zfs' directory maintains a reference of its
+ * own, and any active references underneath are
+ * reflected in the vnode count.
*/
- while (zfsvfs->z_op_cnt) {
- delay(1);
+ if (zfsvfs->z_ctldir == NULL) {
+ if (vfsp->vfs_count > 1)
+ return (EBUSY);
+ } else {
+ if (vfsp->vfs_count > 2 ||
+ zfsvfs->z_ctldir->v_count > 1) {
+ return (EBUSY);
+ }
}
+ }
- zfs_objset_close(zfsvfs);
+ vfsp->vfs_flag |= VFS_UNMOUNTED;
+
+ rw_enter(&zfsvfs->z_unmount_lock, RW_WRITER);
+ rw_enter(&zfsvfs->z_unmount_inactive_lock, RW_WRITER);
- return (0);
- }
/*
- * Check the number of active vnodes in the file system.
- * Our count is maintained in the vfs structure, but the number
- * is off by 1 to indicate a hold on the vfs structure itself.
+ * At this point there are no vops active, and any new vops will
+ * fail with EIO since we have z_unmount_lock for writer (only
+ * relavent for forced unmount).
*
- * The '.zfs' directory maintains a reference of its own, and any active
- * references underneath are reflected in the vnode count.
+ * Release all holds on dbufs.
+ * Note, the dmu can still callback via znode_pageout_func()
+ * which can zfs_znode_free() the znode. So we lock
+ * z_all_znodes; search the list for a held dbuf; drop the lock
+ * (we know zp can't disappear if we hold a dbuf lock) then
+ * regrab the lock and restart.
*/
- if (zfsvfs->z_ctldir == NULL) {
- if (vfsp->vfs_count > 1)
- return (EBUSY);
- } else {
- if (vfsp->vfs_count > 2 ||
- (zfsvfs->z_ctldir->v_count > 1 && !(fflag & MS_FORCE))) {
- return (EBUSY);
+ mutex_enter(&zfsvfs->z_znodes_lock);
+ for (zp = list_head(&zfsvfs->z_all_znodes); zp; zp = nextzp) {
+ nextzp = list_next(&zfsvfs->z_all_znodes, zp);
+ if (zp->z_dbuf_held) {
+ /* dbufs should only be held when force unmounting */
+ zp->z_dbuf_held = 0;
+ mutex_exit(&zfsvfs->z_znodes_lock);
+ dmu_buf_rele(zp->z_dbuf, NULL);
+ /* Start again */
+ mutex_enter(&zfsvfs->z_znodes_lock);
+ nextzp = list_head(&zfsvfs->z_all_znodes);
}
}
+ mutex_exit(&zfsvfs->z_znodes_lock);
- vfsp->vfs_flag |= VFS_UNMOUNTED;
- zfs_objset_close(zfsvfs);
+ /*
+ * Set the unmounted flag and let new vops unblock.
+ * zfs_inactive will have the unmounted behavior, and all other
+ * vops will fail with EIO.
+ */
+ zfsvfs->z_unmounted = B_TRUE;
+ rw_exit(&zfsvfs->z_unmount_lock);
+ rw_exit(&zfsvfs->z_unmount_inactive_lock);
+
+ /*
+ * Unregister properties.
+ */
+ if (!dmu_objset_is_snapshot(os))
+ zfs_unregister_callbacks(zfsvfs);
+
+ /*
+ * Close the zil. NB: Can't close the zil while zfs_inactive
+ * threads are blocked as zil_close can call zfs_inactive.
+ */
+ if (zfsvfs->z_log) {
+ zil_close(zfsvfs->z_log);
+ zfsvfs->z_log = NULL;
+ }
+
+ /*
+ * Evict all dbufs so that cached znodes will be freed
+ */
+ if (dmu_objset_evict_dbufs(os, B_TRUE)) {
+ txg_wait_synced(dmu_objset_pool(zfsvfs->z_os), 0);
+ (void) dmu_objset_evict_dbufs(os, B_FALSE);
+ }
+
+ /*
+ * Finally close the objset
+ */
+ dmu_objset_close(os);
+
+ /*
+ * We can now safely destroy the '.zfs' directory node.
+ */
+ if (zfsvfs->z_ctldir != NULL)
+ zfsctl_destroy(zfsvfs);
return (0);
}
@@ -1177,92 +1223,13 @@ zfs_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
}
static void
-zfs_objset_close(zfsvfs_t *zfsvfs)
-{
- znode_t *zp, *nextzp;
- objset_t *os = zfsvfs->z_os;
-
- /*
- * For forced unmount, at this point all vops except zfs_inactive
- * are erroring EIO. We need to now suspend zfs_inactive threads
- * while we are freeing dbufs before switching zfs_inactive
- * to use behaviour without a objset.
- */
- rw_enter(&zfsvfs->z_um_lock, RW_WRITER);
-
- /*
- * Release all holds on dbufs
- * Note, although we have stopped all other vop threads and
- * zfs_inactive(), the dmu can callback via znode_pageout_func()
- * which can zfs_znode_free() the znode.
- * So we lock z_all_znodes; search the list for a held
- * dbuf; drop the lock (we know zp can't disappear if we hold
- * a dbuf lock; then regrab the lock and restart.
- */
- mutex_enter(&zfsvfs->z_znodes_lock);
- for (zp = list_head(&zfsvfs->z_all_znodes); zp; zp = nextzp) {
- nextzp = list_next(&zfsvfs->z_all_znodes, zp);
- if (zp->z_dbuf_held) {
- /* dbufs should only be held when force unmounting */
- zp->z_dbuf_held = 0;
- mutex_exit(&zfsvfs->z_znodes_lock);
- dmu_buf_rele(zp->z_dbuf, NULL);
- /* Start again */
- mutex_enter(&zfsvfs->z_znodes_lock);
- nextzp = list_head(&zfsvfs->z_all_znodes);
- }
- }
- mutex_exit(&zfsvfs->z_znodes_lock);
-
- /*
- * Unregister properties.
- */
- if (!dmu_objset_is_snapshot(os))
- zfs_unregister_callbacks(zfsvfs);
-
- /*
- * Switch zfs_inactive to behaviour without an objset.
- * It just tosses cached pages and frees the znode & vnode.
- * Then re-enable zfs_inactive threads in that new behaviour.
- */
- zfsvfs->z_unmounted2 = B_TRUE;
- rw_exit(&zfsvfs->z_um_lock); /* re-enable any zfs_inactive threads */
-
- /*
- * Close the zil. Can't close the zil while zfs_inactive
- * threads are blocked as zil_close can call zfs_inactive.
- */
- if (zfsvfs->z_log) {
- zil_close(zfsvfs->z_log);
- zfsvfs->z_log = NULL;
- }
-
- /*
- * Evict all dbufs so that cached znodes will be freed
- */
- if (dmu_objset_evict_dbufs(os, 1)) {
- txg_wait_synced(dmu_objset_pool(zfsvfs->z_os), 0);
- (void) dmu_objset_evict_dbufs(os, 0);
- }
-
- /*
- * Finally close the objset
- */
- dmu_objset_close(os);
-
- /*
- * We can now safely destroy the '.zfs' directory node.
- */
- if (zfsvfs->z_ctldir != NULL)
- zfsctl_destroy(zfsvfs);
-
-}
-
-static void
zfs_freevfs(vfs_t *vfsp)
{
zfsvfs_t *zfsvfs = vfsp->vfs_data;
+ mutex_destroy(&zfsvfs->z_znodes_lock);
+ rw_destroy(&zfsvfs->z_unmount_lock);
+ rw_destroy(&zfsvfs->z_unmount_inactive_lock);
kmem_free(zfsvfs, sizeof (zfsvfs_t));
atomic_add_32(&zfs_active_fs_count, -1);
diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c
index cd592628d9..852555b7f3 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c
@@ -3005,8 +3005,8 @@ zfs_inactive(vnode_t *vp, cred_t *cr)
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
int error;
- rw_enter(&zfsvfs->z_um_lock, RW_READER);
- if (zfsvfs->z_unmounted2) {
+ rw_enter(&zfsvfs->z_unmount_inactive_lock, RW_READER);
+ if (zfsvfs->z_unmounted) {
ASSERT(zp->z_dbuf_held == 0);
if (vn_has_cached_data(vp)) {
@@ -3022,7 +3022,7 @@ zfs_inactive(vnode_t *vp, cred_t *cr)
} else {
mutex_exit(&zp->z_lock);
}
- rw_exit(&zfsvfs->z_um_lock);
+ rw_exit(&zfsvfs->z_unmount_inactive_lock);
VFS_RELE(zfsvfs->z_vfs);
return;
}
@@ -3053,7 +3053,7 @@ zfs_inactive(vnode_t *vp, cred_t *cr)
}
zfs_zinactive(zp);
- rw_exit(&zfsvfs->z_um_lock);
+ rw_exit(&zfsvfs->z_unmount_inactive_lock);
}
/*
diff --git a/usr/src/uts/common/fs/zfs/zvol.c b/usr/src/uts/common/fs/zfs/zvol.c
index 2d9cc65ef8..79e12f7f00 100644
--- a/usr/src/uts/common/fs/zfs/zvol.c
+++ b/usr/src/uts/common/fs/zfs/zvol.c
@@ -114,9 +114,9 @@ int zvol_maxphys = DMU_MAX_ACCESS/2;
static int zvol_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio);
static void
-zvol_size_changed(zvol_state_t *zv, dev_t dev)
+zvol_size_changed(zvol_state_t *zv, major_t maj)
{
- dev = makedevice(getmajor(dev), zv->zv_minor);
+ dev_t dev = makedevice(maj, zv->zv_minor);
VERIFY(ddi_prop_update_int64(dev, zfs_dip,
"Size", zv->zv_volsize) == DDI_SUCCESS);
@@ -315,7 +315,7 @@ zil_replay_func_t *zvol_replay_vector[TX_MAX_TYPE] = {
* Create a minor node for the specified volume.
*/
int
-zvol_create_minor(const char *name, dev_t dev)
+zvol_create_minor(const char *name, major_t maj)
{
zvol_state_t *zv;
objset_t *os;
@@ -452,7 +452,7 @@ zvol_create_minor(const char *name, dev_t dev)
zil_replay(os, zv, &zv->zv_txg_assign, zvol_replay_vector);
- zvol_size_changed(zv, dev);
+ zvol_size_changed(zv, maj);
/* XXX this should handle the possible i/o error */
VERIFY(dsl_prop_register(dmu_objset_ds(zv->zv_objset),
@@ -512,7 +512,7 @@ zvol_remove_minor(const char *name)
}
int
-zvol_set_volsize(const char *name, dev_t dev, uint64_t volsize)
+zvol_set_volsize(const char *name, major_t maj, uint64_t volsize)
{
zvol_state_t *zv;
dmu_tx_t *tx;
@@ -559,7 +559,7 @@ zvol_set_volsize(const char *name, dev_t dev, uint64_t volsize)
if (error == 0) {
zv->zv_volsize = volsize;
- zvol_size_changed(zv, dev);
+ zvol_size_changed(zv, maj);
}
mutex_exit(&zvol_state_lock);
diff --git a/usr/src/uts/common/sys/fs/zfs.h b/usr/src/uts/common/sys/fs/zfs.h
index dd71f174e4..59ed37feaf 100644
--- a/usr/src/uts/common/sys/fs/zfs.h
+++ b/usr/src/uts/common/sys/fs/zfs.h
@@ -98,7 +98,8 @@ typedef enum {
ZPOOL_PROP_AUTOREPLACE,
ZPOOL_PROP_DELEGATION,
ZFS_PROP_VERSION,
- ZPOOL_PROP_NAME /* XXX must be last! */
+ ZPOOL_PROP_NAME,
+ ZFS_NUM_PROPS
} zfs_prop_t;
typedef zfs_prop_t zpool_prop_t;
@@ -160,16 +161,15 @@ int zfs_prop_inheritable(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 **);
uint64_t zpool_prop_default_numeric(zpool_prop_t);
-const char *zfs_prop_perm(zfs_prop_t);
/*
* Property Iterator
*/
typedef zfs_prop_t (*zfs_prop_f)(zfs_prop_t, void *);
typedef zpool_prop_t (*zpool_prop_f)(zpool_prop_t, void *);
-extern zfs_prop_t zfs_prop_iter(zfs_prop_f, void *, boolean_t);
-extern zfs_prop_t zfs_prop_iter_ordered(zfs_prop_f, void *, boolean_t);
-extern zpool_prop_t zpool_prop_iter(zpool_prop_f, void *, boolean_t);
+extern zfs_prop_t zfs_prop_iter(zfs_prop_f, void *);
+extern zfs_prop_t zfs_prop_iter_ordered(zfs_prop_f, void *);
+extern zpool_prop_t zpool_prop_iter(zpool_prop_f, void *);
/*
* On-disk version number.