diff options
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. |