diff options
author | ahrens <none@none> | 2007-08-02 21:23:46 -0700 |
---|---|---|
committer | ahrens <none@none> | 2007-08-02 21:23:46 -0700 |
commit | 91ebeef555ce7f899b6270a3c2df47b51f7ad59a (patch) | |
tree | 7c2ea33b8ecbb85fdd82366244cb0850dbba3287 /usr | |
parent | 03509b53a806cb39ca94c9a1c00f1c6405321554 (diff) | |
download | illumos-joyent-91ebeef555ce7f899b6270a3c2df47b51f7ad59a.tar.gz |
6393351 unique_* could be improved
6553348 assertion failed: ab->b_flags & (1 << 3) at line 2572 of arc.c
6582408 ::arc should accept -k/-m/-g to print in kilo/mega/giga-bytes
6582438 should have generic reader-priority rwlock for spa_config locks
6582441 zfs_cmd_t should only be used to pass arguments to/from userland
6582456 property code is overdue for some spring cleaning
6588564 zpl unmount lock should use regular rwlock
Diffstat (limited to 'usr')
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. |