diff options
Diffstat (limited to 'usr/src')
37 files changed, 749 insertions, 301 deletions
diff --git a/usr/src/cmd/zdb/zdb.c b/usr/src/cmd/zdb/zdb.c index 23cf656ebe..b4294270c8 100644 --- a/usr/src/cmd/zdb/zdb.c +++ b/usr/src/cmd/zdb/zdb.c @@ -367,6 +367,44 @@ dump_zap(objset_t *os, uint64_t object, void *data, size_t size) zap_cursor_fini(&zc); } +/*ARGSUSED*/ +static void +dump_zpldir(objset_t *os, uint64_t object, void *data, size_t size) +{ + zap_cursor_t zc; + zap_attribute_t attr; + const char *typenames[] = { + /* 0 */ "not specified", + /* 1 */ "FIFO", + /* 2 */ "Character Device", + /* 3 */ "3 (invalid)", + /* 4 */ "Directory", + /* 5 */ "5 (invalid)", + /* 6 */ "Block Device", + /* 7 */ "7 (invalid)", + /* 8 */ "Regular File", + /* 9 */ "9 (invalid)", + /* 10 */ "Symbolic Link", + /* 11 */ "11 (invalid)", + /* 12 */ "Socket", + /* 13 */ "Door", + /* 14 */ "Event Port", + /* 15 */ "15 (invalid)", + }; + + dump_zap_stats(os, object); + (void) printf("\n"); + + for (zap_cursor_init(&zc, os, object); + zap_cursor_retrieve(&zc, &attr) == 0; + zap_cursor_advance(&zc)) { + (void) printf("\t\t%s = %lld (type: %s)\n", + attr.za_name, ZFS_DIRENT_OBJ(attr.za_first_integer), + typenames[ZFS_DIRENT_TYPE(attr.za_first_integer)]); + } + zap_cursor_fini(&zc); +} + static void dump_spacemap(objset_t *os, space_map_obj_t *smo, space_map_t *sm) { @@ -878,7 +916,7 @@ static object_viewer_t *object_viewer[DMU_OT_NUMTYPES] = { dump_znode, /* ZFS znode */ dump_acl, /* ZFS ACL */ dump_uint8, /* ZFS plain file */ - dump_zap, /* ZFS directory */ + dump_zpldir, /* ZFS directory */ dump_zap, /* ZFS master node */ dump_zap, /* ZFS delete queue */ dump_uint8, /* zvol object */ @@ -933,13 +971,15 @@ dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header) aux[0] = '\0'; - if (doi.doi_checksum != ZIO_CHECKSUM_INHERIT || verbosity >= 6) + if (doi.doi_checksum != ZIO_CHECKSUM_INHERIT || verbosity >= 6) { (void) snprintf(aux + strlen(aux), sizeof (aux), " (K=%s)", zio_checksum_table[doi.doi_checksum].ci_name); + } - if (doi.doi_compress != ZIO_COMPRESS_INHERIT || verbosity >= 6) + if (doi.doi_compress != ZIO_COMPRESS_INHERIT || verbosity >= 6) { (void) snprintf(aux + strlen(aux), sizeof (aux), " (Z=%s)", zio_compress_table[doi.doi_compress].ci_name); + } (void) printf("%10lld %3u %5s %5s %5s %5s %s%s\n", (u_longlong_t)object, doi.doi_indirection, iblk, dblk, lsize, diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c index fd178add9e..b5a18a0e9a 100644 --- a/usr/src/cmd/zfs/zfs_main.c +++ b/usr/src/cmd/zfs/zfs_main.c @@ -57,6 +57,8 @@ libzfs_handle_t *g_zfs; static FILE *mnttab_file; +static int first_argc; +static char **first_argv; static int zfs_do_clone(int argc, char **argv); static int zfs_do_create(int argc, char **argv); @@ -68,6 +70,7 @@ static int zfs_do_mount(int argc, char **argv); static int zfs_do_rename(int argc, char **argv); static int zfs_do_rollback(int argc, char **argv); static int zfs_do_set(int argc, char **argv); +static int zfs_do_upgrade(int argc, char **argv); static int zfs_do_snapshot(int argc, char **argv); static int zfs_do_unmount(int argc, char **argv); static int zfs_do_share(int argc, char **argv); @@ -100,6 +103,7 @@ typedef enum { HELP_DESTROY, HELP_GET, HELP_INHERIT, + HELP_UPGRADE, HELP_LIST, HELP_MOUNT, HELP_PROMOTE, @@ -146,6 +150,7 @@ static zfs_command_t command_table[] = { { "set", zfs_do_set, HELP_SET }, { "get", zfs_do_get, HELP_GET }, { "inherit", zfs_do_inherit, HELP_INHERIT }, + { "upgrade", zfs_do_upgrade, HELP_UPGRADE }, { NULL }, { "mount", zfs_do_mount, HELP_MOUNT }, { NULL }, @@ -191,6 +196,9 @@ get_usage(zfs_help_t idx) case HELP_INHERIT: return (gettext("\tinherit [-r] <property> " "<filesystem|volume> ...\n")); + case HELP_UPGRADE: + return (gettext("\tupgrade [-v]\n" + "\tupgrade [-r] [-V version] <-a | filesystem ...>\n")); case HELP_LIST: return (gettext("\tlist [-rH] [-o property[,property]...] " "[-t type[,type]...]\n" @@ -1301,6 +1309,208 @@ zfs_do_inherit(int argc, char **argv) return (ret); } +typedef struct upgrade_cbdata { + uint64_t cb_numupgraded; + uint64_t cb_numsamegraded; + uint64_t cb_numdowngradefailed; + uint64_t cb_version; + boolean_t cb_newer; + boolean_t cb_foundone; + char cb_lastfs[ZFS_MAXNAMELEN]; +} upgrade_cbdata_t; + +static int +same_pool(zfs_handle_t *zhp, const char *name) +{ + int len1 = strcspn(name, "/@"); + const char *zhname = zfs_get_name(zhp); + int len2 = strcspn(zhname, "/@"); + + if (len1 != len2) + return (B_FALSE); + return (strncmp(name, zhname, len1) != 0); +} + +static int +upgrade_list_callback(zfs_handle_t *zhp, void *data) +{ + upgrade_cbdata_t *cb = data; + int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); + + /* list if it's old/new */ + if ((!cb->cb_newer && version < ZPL_VERSION) || + (cb->cb_newer && version > SPA_VERSION)) { + char *str; + if (cb->cb_newer) { + str = gettext("The following filesystems are " + "formatted using a newer software version and\n" + "cannot be accessed on the current system.\n\n"); + } else { + str = gettext("The following filesystems are " + "out of date, and can be upgraded. After being\n" + "upgraded, these filesystems (and any 'zfs send' " + "streams generated from\n" + "subsequent snapshots) will no longer be " + "accessible by older software versions.\n\n"); + } + + if (!cb->cb_foundone) { + (void) puts(str); + (void) printf(gettext("VER FILESYSTEM\n")); + (void) printf(gettext("--- ------------\n")); + cb->cb_foundone = B_TRUE; + } + + (void) printf("%2u %s\n", version, zfs_get_name(zhp)); + } + + return (0); +} + +static int +upgrade_set_callback(zfs_handle_t *zhp, void *data) +{ + upgrade_cbdata_t *cb = data; + int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); + + /* upgrade */ + if (version < cb->cb_version) { + char verstr[16]; + (void) snprintf(verstr, sizeof (verstr), "%u", cb->cb_version); + if (cb->cb_lastfs[0] && !same_pool(zhp, cb->cb_lastfs)) { + /* + * If they did "zfs upgrade -a", then we could + * be doing ioctls to different pools. We need + * to log this history once to each pool. + */ + zpool_stage_history(g_zfs, first_argc, first_argv, + B_TRUE, B_FALSE); + } + if (zfs_prop_set(zhp, "version", verstr) == 0) + cb->cb_numupgraded++; + (void) strcpy(cb->cb_lastfs, zfs_get_name(zhp)); + } else if (version > cb->cb_version) { + /* can't downgrade */ + (void) printf(gettext("%s: can not be downgraded; " + "it is already at version %u\n"), + zfs_get_name(zhp), version); + cb->cb_numdowngradefailed++; + } else { + cb->cb_numsamegraded++; + } + return (0); +} + +/* + * zfs upgrade + * zfs upgrade -v + * zfs upgrade [-r] [-V <version>] <-a | filesystem> + */ +static int +zfs_do_upgrade(int argc, char **argv) +{ + boolean_t recurse = B_FALSE; + boolean_t all = B_FALSE; + boolean_t showversions = B_FALSE; + int ret; + upgrade_cbdata_t cb = { 0 }; + char c; + + /* check options */ + while ((c = getopt(argc, argv, "rvV:a")) != -1) { + switch (c) { + case 'r': + recurse = B_TRUE; + break; + case 'v': + showversions = B_TRUE; + break; + case 'V': + if (zfs_prop_string_to_index(ZFS_PROP_VERSION, + optarg, &cb.cb_version) != 0) { + (void) fprintf(stderr, + gettext("invalid version %s\n"), optarg); + usage(B_FALSE); + } + break; + case 'a': + all = B_TRUE; + break; + case '?': + default: + (void) fprintf(stderr, gettext("invalid option '%c'\n"), + optopt); + usage(B_FALSE); + } + } + + argc -= optind; + argv += optind; + + if ((!all && !argc) && (recurse | cb.cb_version)) + usage(B_FALSE); + if (showversions && (recurse || all || cb.cb_version || argc)) + usage(B_FALSE); + if ((all || argc) && (showversions)) + usage(B_FALSE); + if (all && argc) + usage(B_FALSE); + + if (showversions) { + /* Show info on available versions. */ + (void) printf(gettext("The following filesystem versions are " + "supported:\n\n")); + (void) printf(gettext("VER DESCRIPTION\n")); + (void) printf("--- -----------------------------------------" + "---------------\n"); + (void) printf(gettext(" 1 Initial ZFS filesystem version\n")); + (void) printf(gettext(" 2 Enhanced directory entries\n")); + (void) printf(gettext("\nFor more information on a particular " + "version, including supported releases, see:\n\n")); + (void) printf("http://www.opensolaris.org/os/community/zfs/" + "version/zpl/N\n\n"); + (void) printf(gettext("Where 'N' is the version number.\n")); + ret = 0; + } else if (argc || all) { + /* Upgrade filesystems */ + if (cb.cb_version == 0) + cb.cb_version = ZPL_VERSION; + ret = zfs_for_each(argc, argv, recurse, ZFS_TYPE_FILESYSTEM, + NULL, NULL, upgrade_set_callback, &cb, B_TRUE); + (void) printf(gettext("%llu filesystems upgraded\n"), + cb.cb_numupgraded); + if (cb.cb_numsamegraded) { + (void) printf(gettext("%llu filesystems already at " + "this version\n"), + cb.cb_numsamegraded); + } + if (cb.cb_numdowngradefailed != 0) + ret = 1; + } else { + /* List old-version filesytems */ + boolean_t found; + (void) printf(gettext("This system is currently running " + "ZFS filesystem version %llu.\n\n"), ZPL_VERSION); + + ret = zfs_for_each(0, NULL, B_TRUE, ZFS_TYPE_FILESYSTEM, + NULL, NULL, upgrade_list_callback, &cb, B_TRUE); + + found = cb.cb_foundone; + cb.cb_foundone = B_FALSE; + cb.cb_newer = B_TRUE; + + ret = zfs_for_each(0, NULL, B_TRUE, ZFS_TYPE_FILESYSTEM, + NULL, NULL, upgrade_list_callback, &cb, B_TRUE); + + if (!cb.cb_foundone && !found) { + (void) printf(gettext("All filesystems are " + "formatted with the current version.\n")); + } + } + + return (ret); +} + /* * list [-rH] [-o property[,property]...] [-t type[,type]...] * [-s property [-s property]...] [-S property [-S property]...] @@ -3564,6 +3774,9 @@ main(int argc, char **argv) opterr = 0; + first_argc = argc; + first_argv = argv; + if ((g_zfs = libzfs_init()) == NULL) { (void) fprintf(stderr, gettext("internal error: failed to " "initialize ZFS library\n")); diff --git a/usr/src/cmd/zpool/zpool_main.c b/usr/src/cmd/zpool/zpool_main.c index 0bd2146ec5..b0fe69dbc0 100644 --- a/usr/src/cmd/zpool/zpool_main.c +++ b/usr/src/cmd/zpool/zpool_main.c @@ -1221,7 +1221,7 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts, ZPOOL_CONFIG_POOL_STATE, &state) == 0); verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &version) == 0); - if (version > ZFS_VERSION) { + if (version > SPA_VERSION) { (void) fprintf(stderr, gettext("cannot import '%s': pool " "is formatted using a newer ZFS version\n"), name); return (1); @@ -3215,6 +3215,8 @@ typedef struct upgrade_cbdata { int cb_first; int cb_newer; int cb_argc; + uint64_t cb_numupgraded; + uint64_t cb_numsamegraded; char **cb_argv; } upgrade_cbdata_t; @@ -3230,7 +3232,7 @@ upgrade_cb(zpool_handle_t *zhp, void *arg) verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &version) == 0); - if (!cbp->cb_newer && version < ZFS_VERSION) { + if (!cbp->cb_newer && version < SPA_VERSION) { if (!cbp->cb_all) { if (cbp->cb_first) { (void) printf(gettext("The following pools are " @@ -3253,7 +3255,7 @@ upgrade_cb(zpool_handle_t *zhp, void *arg) "'%s'\n"), zpool_get_name(zhp)); } } - } else if (cbp->cb_newer && version > ZFS_VERSION) { + } else if (cbp->cb_newer && version > SPA_VERSION) { assert(!cbp->cb_all); if (cbp->cb_first) { @@ -3291,7 +3293,7 @@ upgrade_one(zpool_handle_t *zhp, void *data) " to upgrade.\n")); return (1); } - if (version == ZFS_VERSION) { + if (version == SPA_VERSION) { (void) printf(gettext("Pool '%s' is already formatted " "using the current version.\n"), zpool_get_name(zhp)); return (0); @@ -3302,7 +3304,7 @@ upgrade_one(zpool_handle_t *zhp, void *data) if (!ret) { (void) printf(gettext("Successfully upgraded '%s' " "from version %llu to version %llu\n"), zpool_get_name(zhp), - (u_longlong_t)version, (u_longlong_t)ZFS_VERSION); + (u_longlong_t)version, (u_longlong_t)SPA_VERSION); } return (ret != 0); @@ -3360,8 +3362,8 @@ zpool_do_upgrade(int argc, char **argv) } } - (void) printf(gettext("This system is currently running ZFS version " - "%llu.\n\n"), ZFS_VERSION); + (void) printf(gettext("This system is currently running " + "ZFS pool version %llu.\n\n"), SPA_VERSION); cb.cb_first = B_TRUE; if (showversions) { (void) printf(gettext("The following versions are " @@ -3461,6 +3463,7 @@ char *hist_event_table[LOG_END] = { "replay_full_sync", "rollback", "snapshot", + "filesystem version upgrade", }; /* diff --git a/usr/src/common/zfs/zfs_deleg.c b/usr/src/common/zfs/zfs_deleg.c index 578d1c6680..d7c3046572 100644 --- a/usr/src/common/zfs/zfs_deleg.c +++ b/usr/src/common/zfs/zfs_deleg.c @@ -80,6 +80,7 @@ char *zfs_deleg_perm_tab[] = { ZFS_DELEG_PERM_SHAREISCSI, ZFS_DELEG_PERM_XATTR, ZFS_DELEG_PERM_COPIES, + ZFS_DELEG_PERM_VERSION, NULL }; diff --git a/usr/src/common/zfs/zfs_prop.c b/usr/src/common/zfs/zfs_prop.c index 887f20a2e1..96dacf49d8 100644 --- a/usr/src/common/zfs/zfs_prop.c +++ b/usr/src/common/zfs/zfs_prop.c @@ -51,6 +51,7 @@ #include <sys/spa.h> #include <sys/zfs_acl.h> #include <sys/zfs_ioctl.h> +#include <sys/zfs_znode.h> #include "zfs_prop.h" #include "zfs_deleg.h" @@ -204,7 +205,10 @@ static prop_desc_t zfs_prop_table[] = { 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 } + 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))) @@ -517,6 +521,13 @@ static zfs_index_t copies_table[] = { { 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) { @@ -533,12 +544,13 @@ zfs_prop_index_table(zfs_prop_t prop) return (acl_inherit_table); case ZFS_PROP_COPIES: return (copies_table); + case ZFS_PROP_VERSION: + return (version_table); default: return (NULL); } } - /* * Tables of index types, plus functions to convert between the user view * (strings) and internal representation (uint64_t). diff --git a/usr/src/grub/grub-0.95/stage2/fsys_zfs.c b/usr/src/grub/grub-0.95/stage2/fsys_zfs.c index 1a7150dfc5..b15779b604 100644 --- a/usr/src/grub/grub-0.95/stage2/fsys_zfs.c +++ b/usr/src/grub/grub-0.95/stage2/fsys_zfs.c @@ -266,8 +266,8 @@ uberblock_verify(uberblock_phys_t *ub, int offset) return (-1); if (uber->ub_magic == UBERBLOCK_MAGIC && - uber->ub_version >= ZFS_VERSION_1 && - uber->ub_version <= ZFS_VERSION) + uber->ub_version >= SPA_VERSION_1 && + uber->ub_version <= SPA_VERSION) return (0); return (-1); @@ -292,11 +292,10 @@ find_bestub(uberblock_phys_t *ub_array, int label) if (uberblock_verify(&ub_array[i], offset) == 0) { if (ubbest == NULL) { ubbest = &ub_array[i]; - } else { - if (vdev_uberblock_compare( - &(ub_array[i].ubp_uberblock), - &(ubbest->ubp_uberblock)) > 0) - ubbest = &ub_array[i]; + } else if (vdev_uberblock_compare( + &(ub_array[i].ubp_uberblock), + &(ubbest->ubp_uberblock)) > 0) { + ubbest = &ub_array[i]; } } } @@ -700,13 +699,18 @@ static int dnode_get_path(dnode_phys_t *mdn, char *path, dnode_phys_t *dn, char *stack) { - uint64_t objnum; + uint64_t objnum, version; char *cname, ch; if (errnum = dnode_get(mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, dn, stack)) return (errnum); + if (errnum = zap_lookup(dn, ZPL_VERSION_STR, &version, stack)) + return (errnum); + if (version > ZPL_VERSION) + return (-1); + if (errnum = zap_lookup(dn, ZFS_ROOT_OBJ, &objnum, stack)) return (errnum); @@ -730,6 +734,7 @@ dnode_get_path(dnode_phys_t *mdn, char *path, dnode_phys_t *dn, if (errnum = zap_lookup(dn, cname, &objnum, stack)) return (errnum); + objnum = ZFS_DIRENT_OBJ(objnum); if (errnum = dnode_get(mdn, objnum, 0, dn, stack)) return (errnum); diff --git a/usr/src/grub/grub-0.95/stage2/zfs-include/zfs.h b/usr/src/grub/grub-0.95/stage2/zfs-include/zfs.h index c590a2f932..8af94bc497 100644 --- a/usr/src/grub/grub-0.95/stage2/zfs-include/zfs.h +++ b/usr/src/grub/grub-0.95/stage2/zfs-include/zfs.h @@ -29,15 +29,15 @@ /* * On-disk version number. */ -#define ZFS_VERSION_1 1ULL -#define ZFS_VERSION_2 2ULL -#define ZFS_VERSION_3 3ULL -#define ZFS_VERSION_4 4ULL -#define ZFS_VERSION_5 5ULL -#define ZFS_VERSION_6 6ULL -#define ZFS_VERSION_7 7ULL -#define ZFS_VERSION_8 8ULL -#define ZFS_VERSION ZFS_VERSION_8 +#define SPA_VERSION_1 1ULL +#define SPA_VERSION_2 2ULL +#define SPA_VERSION_3 3ULL +#define SPA_VERSION_4 4ULL +#define SPA_VERSION_5 5ULL +#define SPA_VERSION_6 6ULL +#define SPA_VERSION_7 7ULL +#define SPA_VERSION_8 8ULL +#define SPA_VERSION SPA_VERSION_8 /* * The following are configuration names used in the nvlist describing a pool's diff --git a/usr/src/grub/grub-0.95/stage2/zfs-include/zfs_znode.h b/usr/src/grub/grub-0.95/stage2/zfs-include/zfs_znode.h index 0f96269c7a..36887aac49 100644 --- a/usr/src/grub/grub-0.95/stage2/zfs-include/zfs_znode.h +++ b/usr/src/grub/grub-0.95/stage2/zfs-include/zfs_znode.h @@ -28,6 +28,11 @@ #define MASTER_NODE_OBJ 1 #define ZFS_ROOT_OBJ "ROOT" +#define ZPL_VERSION_STR "VERSION" + +#define ZPL_VERSION 2ULL + +#define ZFS_DIRENT_OBJ(de) BF64_GET(de, 0, 48) /* * This is the persistent portion of the znode. It is stored diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h index 06ea0a885c..fd51ea23f8 100644 --- a/usr/src/lib/libzfs/common/libzfs.h +++ b/usr/src/lib/libzfs/common/libzfs.h @@ -409,8 +409,6 @@ extern int zfs_promote(zfs_handle_t *); extern const char *zfs_type_to_name(zfs_type_t); extern void zfs_refresh_properties(zfs_handle_t *); extern int zfs_name_valid(const char *, zfs_type_t); -extern int zfs_disable(zfs_handle_t *); -extern int zfs_enable(zfs_handle_t *); extern zfs_handle_t *zfs_path_to_zhandle(libzfs_handle_t *, char *, zfs_type_t); extern boolean_t zfs_dataset_exists(libzfs_handle_t *, const char *, zfs_type_t); diff --git a/usr/src/lib/libzfs/common/libzfs_changelist.c b/usr/src/lib/libzfs/common/libzfs_changelist.c index ad7ce028a1..7a16d015c6 100644 --- a/usr/src/lib/libzfs/common/libzfs_changelist.c +++ b/usr/src/lib/libzfs/common/libzfs_changelist.c @@ -126,8 +126,10 @@ changelist_prefix(prop_changelist_t *clp) (void) zfs_unshare_iscsi(cn->cn_handle); break; } - } else if (zfs_unmount(cn->cn_handle, NULL, clp->cl_flags) != 0) + } else if (zfs_unmount(cn->cn_handle, NULL, + clp->cl_flags) != 0) { ret = -1; + } } return (ret); @@ -542,6 +544,8 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int flags) clp->cl_prop = ZFS_PROP_MOUNTPOINT; } else if (prop == ZFS_PROP_VOLSIZE) { clp->cl_prop = ZFS_PROP_MOUNTPOINT; + } else if (prop == ZFS_PROP_VERSION) { + clp->cl_prop = ZFS_PROP_MOUNTPOINT; } else { clp->cl_prop = prop; } diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c index 5cea7c3fea..6990b20dff 100644 --- a/usr/src/lib/libzfs/common/libzfs_dataset.c +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c @@ -898,6 +898,23 @@ zfs_validate_properties(libzfs_handle_t *hdl, zfs_type_t type, char *pool_name, * Perform some additional checks for specific properties. */ switch (prop) { + case ZFS_PROP_VERSION: + { + int version; + + if (zhp == NULL) + break; + version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); + if (intval < version) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "Can not downgrade; already at version %u"), + version); + (void) zfs_error(hdl, EZFS_BADPROP, errbuf); + goto error; + } + break; + } + case ZFS_PROP_RECORDSIZE: case ZFS_PROP_VOLBLOCKSIZE: /* must be power of two within SPA_{MIN,MAX}BLOCKSIZE */ @@ -1640,6 +1657,7 @@ zfs_coalesce_perm(zfs_handle_t *zhp, zfs_allow_node_t *allownode, } return (0); } + /* * Uggh, this is going to be a bit complicated. * we have an nvlist coming out of the kernel that @@ -2259,20 +2277,6 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, } break; - case ZFS_PROP_RECORDSIZE: - case ZFS_PROP_COMPRESSION: - case ZFS_PROP_ZONED: - case ZFS_PROP_CREATION: - case ZFS_PROP_COMPRESSRATIO: - case ZFS_PROP_REFERENCED: - case ZFS_PROP_USED: - case ZFS_PROP_CREATETXG: - case ZFS_PROP_AVAILABLE: - case ZFS_PROP_VOLSIZE: - case ZFS_PROP_VOLBLOCKSIZE: - *val = getprop_uint64(zhp, prop, source); - break; - case ZFS_PROP_CANMOUNT: *val = getprop_uint64(zhp, prop, source); if (*val == 0) @@ -2299,10 +2303,20 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zfs_source_t *src, break; default: - zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, - "cannot get non-numeric property")); - return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, - dgettext(TEXT_DOMAIN, "internal error"))); + switch (zfs_prop_get_type(prop)) { + case prop_type_number: + case prop_type_boolean: + case prop_type_index: + *val = getprop_uint64(zhp, prop, source); + break; + + case prop_type_string: + default: + zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, + "cannot get non-numeric property")); + return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP, + dgettext(TEXT_DOMAIN, "internal error"))); + } } return (0); @@ -2360,56 +2374,6 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, *src = ZFS_SRC_NONE; switch (prop) { - case ZFS_PROP_ATIME: - case ZFS_PROP_READONLY: - case ZFS_PROP_SETUID: - case ZFS_PROP_ZONED: - case ZFS_PROP_DEVICES: - case ZFS_PROP_EXEC: - case ZFS_PROP_CANMOUNT: - case ZFS_PROP_XATTR: - /* - * Basic boolean values are built on top of - * get_numeric_property(). - */ - if (get_numeric_property(zhp, prop, src, &source, &val) != 0) - return (-1); - nicebool(val, propbuf, proplen); - - break; - - case ZFS_PROP_AVAILABLE: - case ZFS_PROP_RECORDSIZE: - case ZFS_PROP_CREATETXG: - case ZFS_PROP_REFERENCED: - case ZFS_PROP_USED: - case ZFS_PROP_VOLSIZE: - case ZFS_PROP_VOLBLOCKSIZE: - case ZFS_PROP_NUMCLONES: - /* - * Basic numeric values are built on top of - * get_numeric_property(). - */ - if (get_numeric_property(zhp, prop, src, &source, &val) != 0) - return (-1); - if (literal) - (void) snprintf(propbuf, proplen, "%llu", - (u_longlong_t)val); - else - zfs_nicenum(val, propbuf, proplen); - break; - - case ZFS_PROP_COMPRESSION: - case ZFS_PROP_CHECKSUM: - case ZFS_PROP_SNAPDIR: - case ZFS_PROP_ACLMODE: - case ZFS_PROP_ACLINHERIT: - case ZFS_PROP_COPIES: - val = getprop_uint64(zhp, prop, &source); - verify(zfs_prop_index_to_string(prop, val, &strval) == 0); - (void) strlcpy(propbuf, strval, proplen); - break; - case ZFS_PROP_CREATION: /* * 'creation' is a time_t stored in the statistics. We convert @@ -2468,13 +2432,6 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, break; - case ZFS_PROP_SHARENFS: - case ZFS_PROP_SHAREISCSI: - case ZFS_PROP_ISCSIOPTIONS: - (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), - proplen); - break; - case ZFS_PROP_ORIGIN: (void) strlcpy(propbuf, getprop_string(zhp, prop, &source), proplen); @@ -2561,7 +2518,42 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, break; default: - abort(); + switch (zfs_prop_get_type(prop)) { + case prop_type_number: + if (get_numeric_property(zhp, prop, src, + &source, &val) != 0) + return (-1); + if (literal) + (void) snprintf(propbuf, proplen, "%llu", + (u_longlong_t)val); + else + zfs_nicenum(val, propbuf, proplen); + break; + + case prop_type_string: + (void) strlcpy(propbuf, + getprop_string(zhp, prop, &source), proplen); + break; + + case prop_type_boolean: + if (get_numeric_property(zhp, prop, src, + &source, &val) != 0) + return (-1); + nicebool(val, propbuf, proplen); + + break; + + case prop_type_index: + val = getprop_uint64(zhp, prop, &source); + if (zfs_prop_index_to_string(prop, val, + &strval) != 0) + return (-1); + (void) strlcpy(propbuf, strval, proplen); + break; + + default: + abort(); + } } get_source(zhp, src, source, statbuf, statlen); diff --git a/usr/src/lib/libzfs/common/libzfs_import.c b/usr/src/lib/libzfs/common/libzfs_import.c index 97031cbe4e..8b000caf5c 100644 --- a/usr/src/lib/libzfs/common/libzfs_import.c +++ b/usr/src/lib/libzfs/common/libzfs_import.c @@ -682,8 +682,9 @@ error: * Return the offset of the given label. */ static uint64_t -label_offset(size_t size, int l) +label_offset(uint64_t size, int l) { + ASSERT(P2PHASE_TYPED(size, sizeof (vdev_label_t), uint64_t) == 0); return (l * sizeof (vdev_label_t) + (l < VDEV_LABELS / 2 ? 0 : size - VDEV_LABELS * sizeof (vdev_label_t))); } @@ -698,19 +699,20 @@ zpool_read_label(int fd, nvlist_t **config) struct stat64 statbuf; int l; vdev_label_t *label; - uint64_t state, txg; + uint64_t state, txg, size; *config = NULL; if (fstat64(fd, &statbuf) == -1) return (0); + size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t); if ((label = malloc(sizeof (vdev_label_t))) == NULL) return (-1); for (l = 0; l < VDEV_LABELS; l++) { if (pread(fd, label, sizeof (vdev_label_t), - label_offset(statbuf.st_size, l)) != sizeof (vdev_label_t)) + label_offset(size, l)) != sizeof (vdev_label_t)) continue; if (nvlist_unpack(label->vl_vdev_phys.vp_nvlist, diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c index 9c1d197f4d..daf435126a 100644 --- a/usr/src/lib/libzfs/common/libzfs_pool.c +++ b/usr/src/lib/libzfs/common/libzfs_pool.c @@ -534,7 +534,7 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, "cannot add to '%s'"), zhp->zpool_name); - if (zpool_get_version(zhp) < ZFS_VERSION_SPARES && + if (zpool_get_version(zhp) < SPA_VERSION_SPARES && nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be " @@ -2183,7 +2183,7 @@ zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval) dgettext(TEXT_DOMAIN, "cannot set property for '%s'"), zhp->zpool_name); - if (zpool_get_version(zhp) < ZFS_VERSION_BOOTFS) { + if (zpool_get_version(zhp) < SPA_VERSION_BOOTFS) { zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, "pool must be " "upgraded to support pool properties")); @@ -2230,7 +2230,7 @@ zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop) uint64_t value; nvlist_t *nvp; - if (zpool_get_version(zhp) < ZFS_VERSION_BOOTFS) + if (zpool_get_version(zhp) < SPA_VERSION_BOOTFS) return (0); if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) @@ -2267,7 +2267,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *propbuf, (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, "cannot get property '%s'"), zpool_prop_to_name(prop)); - if (zpool_get_version(zhp) < ZFS_VERSION_BOOTFS) { + if (zpool_get_version(zhp) < SPA_VERSION_BOOTFS) { zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN, "pool must be " "upgraded to support pool properties")); diff --git a/usr/src/lib/libzfs/common/libzfs_status.c b/usr/src/lib/libzfs/common/libzfs_status.c index 97a81c35bb..6e2065ea36 100644 --- a/usr/src/lib/libzfs/common/libzfs_status.c +++ b/usr/src/lib/libzfs/common/libzfs_status.c @@ -264,7 +264,7 @@ check_status(nvlist_t *config, boolean_t isimport) /* * Outdated, but usable, version */ - if (version < ZFS_VERSION) + if (version < SPA_VERSION) return (ZPOOL_STATUS_VERSION_OLDER); return (ZPOOL_STATUS_OK); diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers index d870f339f8..53e75e9323 100644 --- a/usr/src/lib/libzfs/common/mapfile-vers +++ b/usr/src/lib/libzfs/common/mapfile-vers @@ -85,6 +85,7 @@ SUNWprivate_1.1 { zfs_prop_iter; zfs_prop_readonly; zfs_prop_set; + zfs_prop_string_to_index; zfs_prop_to_name; zfs_prop_user; zfs_prop_valid_for_type; diff --git a/usr/src/uts/common/fs/zfs/bplist.c b/usr/src/uts/common/fs/zfs/bplist.c index 4442b1f28a..ecab27dd1c 100644 --- a/usr/src/uts/common/fs/zfs/bplist.c +++ b/usr/src/uts/common/fs/zfs/bplist.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. */ @@ -47,7 +47,7 @@ bplist_create(objset_t *mos, int blocksize, dmu_tx_t *tx) { int size; - size = spa_version(dmu_objset_spa(mos)) < ZFS_VERSION_BPLIST_ACCOUNT ? + size = spa_version(dmu_objset_spa(mos)) < SPA_VERSION_BPLIST_ACCOUNT ? BPLIST_SIZE_V0 : sizeof (bplist_phys_t); return (dmu_object_alloc(mos, DMU_OT_BPLIST, blocksize, diff --git a/usr/src/uts/common/fs/zfs/dnode.c b/usr/src/uts/common/fs/zfs/dnode.c index 1fe144d09e..8e3ded7f94 100644 --- a/usr/src/uts/common/fs/zfs/dnode.c +++ b/usr/src/uts/common/fs/zfs/dnode.c @@ -1181,7 +1181,7 @@ dnode_diduse_space(dnode_t *dn, int64_t delta) ASSERT3U(space, >=, -delta); /* no underflow */ } space += delta; - if (spa_version(dn->dn_objset->os_spa) < ZFS_VERSION_DNODE_BYTES) { + if (spa_version(dn->dn_objset->os_spa) < SPA_VERSION_DNODE_BYTES) { ASSERT((dn->dn_phys->dn_flags & DNODE_FLAG_USED_BYTES) == 0); ASSERT3U(P2PHASE(space, 1<<DEV_BSHIFT), ==, 0); dn->dn_phys->dn_used = space >> DEV_BSHIFT; diff --git a/usr/src/uts/common/fs/zfs/dsl_dataset.c b/usr/src/uts/common/fs/zfs/dsl_dataset.c index e5bfe207b2..6a4baa8c76 100644 --- a/usr/src/uts/common/fs/zfs/dsl_dataset.c +++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c @@ -268,7 +268,7 @@ dsl_dataset_get_snapname(dsl_dataset_t *ds) return (err); headphys = headdbuf->db_data; err = zap_value_search(dp->dp_meta_objset, - headphys->ds_snapnames_zapobj, ds->ds_object, ds->ds_snapname); + headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname); dmu_buf_rele(headdbuf, FTAG); return (err); } diff --git a/usr/src/uts/common/fs/zfs/dsl_dir.c b/usr/src/uts/common/fs/zfs/dsl_dir.c index d15c7772c3..d7fe638d7d 100644 --- a/usr/src/uts/common/fs/zfs/dsl_dir.c +++ b/usr/src/uts/common/fs/zfs/dsl_dir.c @@ -126,17 +126,15 @@ dsl_dir_open_obj(dsl_pool_t *dp, uint64_t ddobj, uint64_t foundobj; err = zap_lookup(dp->dp_meta_objset, - dd->dd_parent->dd_phys-> - dd_child_dir_zapobj, + dd->dd_parent->dd_phys->dd_child_dir_zapobj, tail, sizeof (foundobj), 1, &foundobj); ASSERT(err || foundobj == ddobj); #endif (void) strcpy(dd->dd_myname, tail); } else { err = zap_value_search(dp->dp_meta_objset, - dd->dd_parent->dd_phys-> - dd_child_dir_zapobj, - ddobj, dd->dd_myname); + dd->dd_parent->dd_phys->dd_child_dir_zapobj, + ddobj, 0, dd->dd_myname); } if (err) { dsl_dir_close(dd->dd_parent, dd); diff --git a/usr/src/uts/common/fs/zfs/dsl_synctask.c b/usr/src/uts/common/fs/zfs/dsl_synctask.c index e1b5b49faa..810d449938 100644 --- a/usr/src/uts/common/fs/zfs/dsl_synctask.c +++ b/usr/src/uts/common/fs/zfs/dsl_synctask.c @@ -50,6 +50,7 @@ dsl_sync_task_group_create(dsl_pool_t *dp) list_create(&dstg->dstg_tasks, sizeof (dsl_sync_task_t), offsetof(dsl_sync_task_t, dst_node)); dstg->dstg_pool = dp; + dstg->dstg_cr = CRED(); return (dstg); } @@ -68,7 +69,6 @@ dsl_sync_task_create(dsl_sync_task_group_t *dstg, dst->dst_syncfunc = syncfunc; dst->dst_arg1 = arg1; dst->dst_arg2 = arg2; - dst->dst_cr = CRED(); list_insert_tail(&dstg->dstg_tasks, dst); dstg->dstg_space += blocks_modified << DST_AVG_BLKSHIFT; @@ -125,6 +125,16 @@ top: } void +dsl_sync_task_group_nowait(dsl_sync_task_group_t *dstg, dmu_tx_t *tx) +{ + uint64_t txg; + + dstg->dstg_nowaiter = B_TRUE; + txg = dmu_tx_get_txg(tx); + VERIFY(0 == txg_list_add(&dstg->dstg_pool->dp_sync_tasks, dstg, txg)); +} + +void dsl_sync_task_group_destroy(dsl_sync_task_group_t *dstg) { dsl_sync_task_t *dst; @@ -174,12 +184,15 @@ dsl_sync_task_group_sync(dsl_sync_task_group_t *dstg, dmu_tx_t *tx) for (dst = list_head(&dstg->dstg_tasks); dst; dst = list_next(&dstg->dstg_tasks, dst)) { dst->dst_syncfunc(dst->dst_arg1, dst->dst_arg2, - dst->dst_cr, tx); + dstg->dstg_cr, tx); } } rw_exit(&dstg->dstg_pool->dp_config_rwlock); dsl_dir_tempreserve_clear(tr_cookie, tx); + + if (dstg->dstg_nowaiter) + dsl_sync_task_group_destroy(dstg); } int @@ -197,3 +210,16 @@ dsl_sync_task_do(dsl_pool_t *dp, dsl_sync_task_group_destroy(dstg); return (err); } + +void +dsl_sync_task_do_nowait(dsl_pool_t *dp, + dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc, + void *arg1, void *arg2, int blocks_modified, dmu_tx_t *tx) +{ + dsl_sync_task_group_t *dstg; + + dstg = dsl_sync_task_group_create(dp); + dsl_sync_task_create(dstg, checkfunc, syncfunc, + arg1, arg2, blocks_modified); + dsl_sync_task_group_nowait(dstg, tx); +} diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c index 72015135e7..ba56215562 100644 --- a/usr/src/uts/common/fs/zfs/spa.c +++ b/usr/src/uts/common/fs/zfs/spa.c @@ -475,7 +475,7 @@ spa_load(spa_t *spa, nvlist_t *config, spa_load_state_t state, int mosconfig) * it's not present treat it as the initial version. */ if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &version) != 0) - version = ZFS_VERSION_INITIAL; + version = SPA_VERSION_INITIAL; (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG, &spa->spa_config_txg); @@ -551,7 +551,7 @@ spa_load(spa_t *spa, nvlist_t *config, spa_load_state_t state, int mosconfig) /* * If the pool is newer than the code, we can't open it. */ - if (ub->ub_version > ZFS_VERSION) { + if (ub->ub_version > SPA_VERSION) { vdev_set_state(rvd, B_TRUE, VDEV_STATE_CANT_OPEN, VDEV_AUX_VERSION_NEWER); error = ENOTSUP; @@ -707,7 +707,7 @@ spa_load(spa_t *spa, nvlist_t *config, spa_load_state_t state, int mosconfig) goto out; } if (error == 0) { - ASSERT(spa_version(spa) >= ZFS_VERSION_SPARES); + ASSERT(spa_version(spa) >= SPA_VERSION_SPARES); if (load_nvlist(spa, spa->spa_spares_object, &spa->spa_sparelist) != 0) { vdev_set_state(rvd, B_TRUE, VDEV_STATE_CANT_OPEN, @@ -1089,7 +1089,7 @@ spa_validate_spares(spa_t *spa, nvlist_t *nvroot, uint64_t crtxg, int mode) * Make sure the pool is formatted with a version that supports hot * spares. */ - if (spa_version(spa) < ZFS_VERSION_SPARES) + if (spa_version(spa) < SPA_VERSION_SPARES) return (ENOTSUP); /* @@ -1164,7 +1164,7 @@ spa_create(const char *pool, nvlist_t *nvroot, const char *altroot) spa_activate(spa); spa->spa_uberblock.ub_txg = txg - 1; - spa->spa_uberblock.ub_version = ZFS_VERSION; + spa->spa_uberblock.ub_version = SPA_VERSION; spa->spa_ubsync = spa->spa_uberblock; /* @@ -1928,7 +1928,7 @@ spa_vdev_detach(spa_t *spa, uint64_t guid, int replace_done) } ASSERT(pvd->vdev_ops != &vdev_spare_ops || - spa_version(spa) >= ZFS_VERSION_SPARES); + spa_version(spa) >= SPA_VERSION_SPARES); /* * Only mirror, replacing, and spare vdevs support detach. @@ -3052,11 +3052,11 @@ spa_sync(spa_t *spa, uint64_t txg) tx = dmu_tx_create_assigned(dp, txg); /* - * If we are upgrading to ZFS_VERSION_RAIDZ_DEFLATE this txg, + * If we are upgrading to SPA_VERSION_RAIDZ_DEFLATE this txg, * set spa_deflate if we have no raid-z vdevs. */ - if (spa->spa_ubsync.ub_version < ZFS_VERSION_RAIDZ_DEFLATE && - spa->spa_uberblock.ub_version >= ZFS_VERSION_RAIDZ_DEFLATE) { + if (spa->spa_ubsync.ub_version < SPA_VERSION_RAIDZ_DEFLATE && + spa->spa_uberblock.ub_version >= SPA_VERSION_RAIDZ_DEFLATE) { int i; for (i = 0; i < rvd->vdev_children; i++) { @@ -3273,9 +3273,9 @@ spa_upgrade(spa_t *spa) * future version would result in an unopenable pool, this shouldn't be * possible. */ - ASSERT(spa->spa_uberblock.ub_version <= ZFS_VERSION); + ASSERT(spa->spa_uberblock.ub_version <= SPA_VERSION); - spa->spa_uberblock.ub_version = ZFS_VERSION; + spa->spa_uberblock.ub_version = SPA_VERSION; vdev_config_dirty(spa->spa_root_vdev); spa_config_exit(spa, FTAG); diff --git a/usr/src/uts/common/fs/zfs/spa_history.c b/usr/src/uts/common/fs/zfs/spa_history.c index 7d44242596..f3fc5f3b35 100644 --- a/usr/src/uts/common/fs/zfs/spa_history.c +++ b/usr/src/uts/common/fs/zfs/spa_history.c @@ -188,7 +188,7 @@ spa_history_zone() /* * Write out a history event. */ -void +static void spa_history_log_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) { spa_t *spa = arg1; @@ -203,9 +203,6 @@ spa_history_log_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) char *record_packed = NULL; int ret; - if (history_str == NULL) - return; - /* * If we have an older pool that doesn't have a command * history object, create it now. @@ -279,6 +276,11 @@ spa_history_log_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) nvlist_free(nvrecord); kmem_free(record_packed, reclen); dmu_buf_rele(dbp, FTAG); + + if (hap->ha_log_type == LOG_INTERNAL) { + kmem_free((void*)hap->ha_history_str, HIS_MAX_RECORD_LEN); + kmem_free(hap, sizeof (history_arg_t)); + } } /* @@ -289,6 +291,8 @@ spa_history_log(spa_t *spa, const char *history_str, history_log_type_t what) { history_arg_t ha; + ASSERT(what != LOG_INTERNAL); + ha.ha_history_str = history_str; ha.ha_log_type = what; (void) strlcpy(ha.ha_zone, spa_history_zone(), sizeof (ha.ha_zone)); @@ -388,20 +392,27 @@ void spa_history_internal_log(history_internal_events_t event, spa_t *spa, dmu_tx_t *tx, cred_t *cr, const char *fmt, ...) { - history_arg_t ha; + history_arg_t *hap; char *str; va_list adx; + hap = kmem_alloc(sizeof (history_arg_t), KM_SLEEP); str = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); va_start(adx, fmt); (void) vsnprintf(str, HIS_MAX_RECORD_LEN, fmt, adx); va_end(adx); - ha.ha_log_type = LOG_INTERNAL; - ha.ha_history_str = str; - ha.ha_event = event; - ha.ha_zone[0] = '\0'; - spa_history_log_sync(spa, &ha, cr, tx); - kmem_free(str, HIS_MAX_RECORD_LEN); + hap->ha_log_type = LOG_INTERNAL; + hap->ha_history_str = str; + hap->ha_event = event; + hap->ha_zone[0] = '\0'; + + if (dmu_tx_is_syncing(tx)) { + spa_history_log_sync(spa, hap, cr, tx); + } else { + dsl_sync_task_do_nowait(spa_get_dsl(spa), NULL, + spa_history_log_sync, spa, hap, 0, tx); + } + /* spa_history_log_sync() will free hap and str */ } diff --git a/usr/src/uts/common/fs/zfs/spa_misc.c b/usr/src/uts/common/fs/zfs/spa_misc.c index 578f89e333..d2ba6a1079 100644 --- a/usr/src/uts/common/fs/zfs/spa_misc.c +++ b/usr/src/uts/common/fs/zfs/spa_misc.c @@ -1016,11 +1016,11 @@ int spa_max_replication(spa_t *spa) { /* - * As of ZFS_VERSION == ZFS_VERSION_DITTO_BLOCKS, we are able to + * As of SPA_VERSION == SPA_VERSION_DITTO_BLOCKS, we are able to * handle BPs with more than one DVA allocated. Set our max * replication level accordingly. */ - if (spa_version(spa) < ZFS_VERSION_DITTO_BLOCKS) + if (spa_version(spa) < SPA_VERSION_DITTO_BLOCKS) return (1); return (MIN(SPA_DVAS_PER_BP, spa_max_replication_override)); } 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 87a8526716..1cc22b3dc8 100644 --- a/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h +++ b/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h @@ -71,6 +71,7 @@ extern "C" { #define ZFS_DELEG_PERM_SHAREISCSI "shareiscsi" #define ZFS_DELEG_PERM_XATTR "xattr" #define ZFS_DELEG_PERM_COPIES "copies" +#define ZFS_DELEG_PERM_VERSION "version" int dsl_deleg_get(const char *ddname, nvlist_t **nvp); int dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset); diff --git a/usr/src/uts/common/fs/zfs/sys/dsl_synctask.h b/usr/src/uts/common/fs/zfs/sys/dsl_synctask.h index 9125c30b42..4995bfe5ac 100644 --- a/usr/src/uts/common/fs/zfs/sys/dsl_synctask.h +++ b/usr/src/uts/common/fs/zfs/sys/dsl_synctask.h @@ -46,7 +46,6 @@ typedef struct dsl_sync_task { dsl_syncfunc_t *dst_syncfunc; void *dst_arg1; void *dst_arg2; - cred_t *dst_cr; int dst_err; } dsl_sync_task_t; @@ -54,9 +53,11 @@ typedef struct dsl_sync_task_group { txg_node_t dstg_node; list_t dstg_tasks; struct dsl_pool *dstg_pool; + cred_t *dstg_cr; uint64_t dstg_txg; int dstg_err; int dstg_space; + boolean_t dstg_nowaiter; } dsl_sync_task_group_t; dsl_sync_task_group_t *dsl_sync_task_group_create(struct dsl_pool *dp); @@ -64,12 +65,16 @@ void dsl_sync_task_create(dsl_sync_task_group_t *dstg, dsl_checkfunc_t *, dsl_syncfunc_t *, void *arg1, void *arg2, int blocks_modified); int dsl_sync_task_group_wait(dsl_sync_task_group_t *dstg); +void dsl_sync_task_group_nowait(dsl_sync_task_group_t *dstg, dmu_tx_t *tx); void dsl_sync_task_group_destroy(dsl_sync_task_group_t *dstg); void dsl_sync_task_group_sync(dsl_sync_task_group_t *dstg, dmu_tx_t *tx); int dsl_sync_task_do(struct dsl_pool *dp, dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc, void *arg1, void *arg2, int blocks_modified); +void dsl_sync_task_do_nowait(struct dsl_pool *dp, + dsl_checkfunc_t *checkfunc, dsl_syncfunc_t *syncfunc, + void *arg1, void *arg2, int blocks_modified, dmu_tx_t *tx); #ifdef __cplusplus } diff --git a/usr/src/uts/common/fs/zfs/sys/uberblock_impl.h b/usr/src/uts/common/fs/zfs/sys/uberblock_impl.h index ab0f2dcf8c..55a0dd5aec 100644 --- a/usr/src/uts/common/fs/zfs/sys/uberblock_impl.h +++ b/usr/src/uts/common/fs/zfs/sys/uberblock_impl.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. */ @@ -49,7 +49,7 @@ extern "C" { struct uberblock { uint64_t ub_magic; /* UBERBLOCK_MAGIC */ - uint64_t ub_version; /* ZFS_VERSION */ + uint64_t ub_version; /* SPA_VERSION */ uint64_t ub_txg; /* txg of last sync */ uint64_t ub_guid_sum; /* sum of all vdev guids */ uint64_t ub_timestamp; /* UTC time of last sync */ diff --git a/usr/src/uts/common/fs/zfs/sys/zap.h b/usr/src/uts/common/fs/zfs/sys/zap.h index f89d9385ea..d194705987 100644 --- a/usr/src/uts/common/fs/zfs/sys/zap.h +++ b/usr/src/uts/common/fs/zfs/sys/zap.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. */ @@ -191,11 +191,13 @@ int zap_count(objset_t *ds, uint64_t zapobj, uint64_t *count); /* - * Returns (in name) the name of the entry whose value + * Returns (in name) the name of the entry whose (value & mask) * (za_first_integer) is value, or ENOENT if not found. The string - * pointed to by name must be at least 256 bytes long. + * pointed to by name must be at least 256 bytes long. If mask==0, the + * match must be exact (ie, same as mask=-1ULL). */ -int zap_value_search(objset_t *os, uint64_t zapobj, uint64_t value, char *name); +int zap_value_search(objset_t *os, uint64_t zapobj, + uint64_t value, uint64_t mask, char *name); struct zap; struct zap_leaf; 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 d06915dfb9..912416a838 100644 --- a/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h +++ b/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h @@ -61,6 +61,7 @@ struct zfsvfs { vnode_t *z_ctldir; /* .zfs directory pointer */ boolean_t z_show_ctldir; /* expose .zfs in the root dir */ boolean_t z_issnap; /* true if this is a snapshot */ + uint64_t z_version; #define ZFS_OBJ_MTX_SZ 64 kmutex_t z_hold_mtx[ZFS_OBJ_MTX_SZ]; /* znode hold locks */ }; 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 b53eed9be3..4b731ba320 100644 --- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h +++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h @@ -54,23 +54,11 @@ extern "C" { /* * special attributes for master node. */ - #define ZFS_FSID "FSID" #define ZFS_UNLINKED_SET "DELETE_QUEUE" #define ZFS_ROOT_OBJ "ROOT" -#define ZPL_VERSION_OBJ "VERSION" -#define ZFS_PROP_BLOCKPERPAGE "BLOCKPERPAGE" -#define ZFS_PROP_NOGROWBLOCKS "NOGROWBLOCKS" - -#define ZFS_FLAG_BLOCKPERPAGE 0x1 -#define ZFS_FLAG_NOGROWBLOCKS 0x2 - -/* - * ZPL version - rev'd whenever an incompatible on-disk format change - * occurs. Independent of SPA/DMU/ZAP versioning. - */ +#define ZPL_VERSION_STR "VERSION" -#define ZPL_VERSION 1ULL #define ZFS_MAX_BLOCKSIZE (SPA_MAXBLOCKSIZE) @@ -85,14 +73,18 @@ extern "C" { #define ZFS_MAXNAMELEN (MAXNAMELEN - 1) /* + * Convert mode bits (zp_mode) to BSD-style DT_* values for storing in + * the directory entries. + */ +#define IFTODT(mode) (((mode) & S_IFMT) >> 12) + +/* * The directory entry has the type (currently unused on Solaris) in the * top 4 bits, and the object number in the low 48 bits. The "middle" * 12 bits are unused. */ #define ZFS_DIRENT_TYPE(de) BF64_GET(de, 60, 4) #define ZFS_DIRENT_OBJ(de) BF64_GET(de, 0, 48) -#define ZFS_DIRENT_MAKE(type, obj) (((uint64_t)type << 60) | obj) - /* * This is the persistent portion of the znode. It is stored @@ -248,7 +240,7 @@ typedef struct znode { extern int zfs_init_fs(zfsvfs_t *, znode_t **, cred_t *); extern void zfs_set_dataprop(objset_t *); -extern void zfs_create_fs(objset_t *os, cred_t *cr, dmu_tx_t *tx); +extern void zfs_create_fs(objset_t *os, cred_t *cr, uint64_t, dmu_tx_t *tx); extern void zfs_time_stamper(znode_t *, uint_t, dmu_tx_t *); extern void zfs_time_stamper_locked(znode_t *, uint_t, dmu_tx_t *); extern void zfs_grow_blocksize(znode_t *, uint64_t, dmu_tx_t *); @@ -263,6 +255,8 @@ extern void zfs_remove_op_tables(); extern int zfs_create_op_tables(); extern int zfs_sync(vfs_t *vfsp, short flag, cred_t *cr); extern dev_t zfs_cmpldev(uint64_t); +extern int zfs_get_stats(objset_t *os, nvlist_t *nv); +extern int zfs_set_version(const char *name, uint64_t newvers); extern void zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, int txtype, znode_t *dzp, znode_t *zp, char *name); diff --git a/usr/src/uts/common/fs/zfs/vdev.c b/usr/src/uts/common/fs/zfs/vdev.c index 9269311cf4..84b0325f34 100644 --- a/usr/src/uts/common/fs/zfs/vdev.c +++ b/usr/src/uts/common/fs/zfs/vdev.c @@ -395,14 +395,14 @@ vdev_alloc(spa_t *spa, vdev_t **vdp, nvlist_t *nv, vdev_t *parent, uint_t id, * Older versions can only support 1 parity device. */ if (nparity == 2 && - spa_version(spa) < ZFS_VERSION_RAID6) + spa_version(spa) < SPA_VERSION_RAID6) return (ENOTSUP); } else { /* * We require the parity to be specified for SPAs that * support multiple parity levels. */ - if (spa_version(spa) >= ZFS_VERSION_RAID6) + if (spa_version(spa) >= SPA_VERSION_RAID6) return (EINVAL); /* * Otherwise, we default to 1 parity device for RAID-Z. @@ -1361,7 +1361,7 @@ vdev_validate_spare(vdev_t *vd) } if (nvlist_lookup_uint64(label, ZPOOL_CONFIG_VERSION, &version) != 0 || - version > ZFS_VERSION || + version > SPA_VERSION || nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID, &guid) != 0 || guid != vd->vdev_guid || nvlist_lookup_uint64(label, ZPOOL_CONFIG_POOL_STATE, &state) != 0) { diff --git a/usr/src/uts/common/fs/zfs/vdev_label.c b/usr/src/uts/common/fs/zfs/vdev_label.c index 7c5487bf1a..0158228a34 100644 --- a/usr/src/uts/common/fs/zfs/vdev_label.c +++ b/usr/src/uts/common/fs/zfs/vdev_label.c @@ -153,6 +153,7 @@ uint64_t vdev_label_offset(uint64_t psize, int l, uint64_t offset) { ASSERT(offset < sizeof (vdev_label_t)); + ASSERT(P2PHASE_TYPED(psize, sizeof (vdev_label_t), uint64_t) == 0); return (offset + l * sizeof (vdev_label_t) + (l < VDEV_LABELS / 2 ? 0 : psize - VDEV_LABELS * sizeof (vdev_label_t))); @@ -223,7 +224,7 @@ vdev_config_generate(spa_t *spa, vdev_t *vd, boolean_t getstats, */ ASSERT(vd->vdev_nparity == 1 || (vd->vdev_nparity == 2 && - spa_version(spa) >= ZFS_VERSION_RAID6)); + spa_version(spa) >= SPA_VERSION_RAID6)); /* * Note that we'll add the nparity tag even on storage pools diff --git a/usr/src/uts/common/fs/zfs/zap.c b/usr/src/uts/common/fs/zfs/zap.c index 715de6adf4..7dfe44baba 100644 --- a/usr/src/uts/common/fs/zfs/zap.c +++ b/usr/src/uts/common/fs/zfs/zap.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. */ @@ -897,17 +897,21 @@ fzap_remove(zap_t *zap, const char *name, dmu_tx_t *tx) } int -zap_value_search(objset_t *os, uint64_t zapobj, uint64_t value, char *name) +zap_value_search(objset_t *os, uint64_t zapobj, uint64_t value, uint64_t mask, + char *name) { zap_cursor_t zc; zap_attribute_t *za; int err; + if (mask == 0) + mask = -1ULL; + za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); for (zap_cursor_init(&zc, os, zapobj); (err = zap_cursor_retrieve(&zc, za)) == 0; zap_cursor_advance(&zc)) { - if (za->za_first_integer == value) { + if ((za->za_first_integer & mask) == (value & mask)) { (void) strcpy(name, za->za_name); break; } diff --git a/usr/src/uts/common/fs/zfs/zfs_dir.c b/usr/src/uts/common/fs/zfs/zfs_dir.c index bf459719c5..bcaa6fd4b5 100644 --- a/usr/src/uts/common/fs/zfs/zfs_dir.c +++ b/usr/src/uts/common/fs/zfs/zfs_dir.c @@ -516,6 +516,15 @@ zfs_rmnode(znode_t *zp) VN_RELE(ZTOV(xzp)); } +static uint64_t +zfs_dirent(znode_t *zp) +{ + uint64_t de = zp->z_id; + if (zp->z_zfsvfs->z_version >= ZPL_VERSION_DIRENT_TYPE) + de |= IFTODT((zp)->z_phys->zp_mode) << 60; + return (de); +} + /* * Link zp into dl. Can only fail if zp has been unlinked. */ @@ -552,10 +561,7 @@ zfs_link_create(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag) zfs_time_stamper_locked(dzp, CONTENT_MODIFIED, tx); mutex_exit(&dzp->z_lock); - /* - * MacOS X will fill in the 4-bit object type here. - */ - value = ZFS_DIRENT_MAKE(0, zp->z_id); + value = zfs_dirent(zp); error = zap_add(zp->z_zfsvfs->z_os, dzp->z_id, dl->dl_name, 8, 1, &value, tx); ASSERT(error == 0); diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c index 560a943cd7..dcd9853ed8 100644 --- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c +++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c @@ -62,6 +62,7 @@ #include <sys/zfs_ctldir.h> #include <sys/zvol.h> #include <sharefs/share.h> +#include <sys/zfs_znode.h> #include "zfs_namecheck.h" #include "zfs_prop.h" @@ -82,9 +83,9 @@ typedef struct zfs_ioc_vec { zfs_ioc_func_t *zvec_func; zfs_secpolicy_func_t *zvec_secpolicy; enum { - no_name, - pool_name, - dataset_name + NO_NAME, + POOL_NAME, + DATASET_NAME } zvec_namecheck; boolean_t zvec_his_log; } zfs_ioc_vec_t; @@ -135,6 +136,10 @@ zfs_log_history(zfs_cmd_t *zc) if (zc->zc_history == NULL) return; + if (zc->zc_history_offset != LOG_CMD_POOL_CREATE && + zc->zc_history_offset != LOG_CMD_NORMAL) + return; + buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP); if (copyinstr((void *)(uintptr_t)zc->zc_history, buf, HIS_MAX_RECORD_LEN, NULL) != 0) { @@ -154,7 +159,7 @@ zfs_log_history(zfs_cmd_t *zc) return; } - if (spa_version(spa) >= ZFS_VERSION_ZPOOL_HISTORY) + if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY) (void) spa_history_log(spa, buf, zc->zc_history_offset); spa_close(spa, FTAG); @@ -521,8 +526,6 @@ zfs_secpolicy_snapshot(zfs_cmd_t *zc, cred_t *cr) return (zfs_secpolicy_snapshot_perms(zc->zc_name, cr)); } - - static int zfs_secpolicy_create(zfs_cmd_t *zc, cred_t *cr) { @@ -847,7 +850,7 @@ zfs_ioc_pool_get_history(zfs_cmd_t *zc) if ((error = spa_open(zc->zc_name, &spa, FTAG)) != 0) return (error); - if (spa_version(spa) < ZFS_VERSION_ZPOOL_HISTORY) { + if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY) { spa_close(spa, FTAG); return (ENOTSUP); } @@ -1052,14 +1055,17 @@ retry: (error = dsl_prop_get_all(os, &nv)) == 0) { dmu_objset_stats(os, nv); /* - * NB: zvol_get_stats() will read the objset contents, + * NB: {zpl,zvol}_get_stats() will read the objset contents, * which we aren't supposed to do with a * DS_MODE_STANDARD open, because it could be * inconsistent. So this is a bit of a workaround... */ - if (!zc->zc_objset_stats.dds_inconsistent && - dmu_objset_type(os) == DMU_OST_ZVOL) - VERIFY(zvol_get_stats(os, nv) == 0); + if (!zc->zc_objset_stats.dds_inconsistent) { + if (dmu_objset_type(os) == DMU_OST_ZVOL) + VERIFY(zvol_get_stats(os, nv) == 0); + else if (dmu_objset_type(os) == DMU_OST_ZFS) + (void) zfs_get_stats(os, nv); + } error = put_nvlist(zc, nv); nvlist_free(nv); } @@ -1266,7 +1272,7 @@ zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl) if (spa_open(p, &spa, FTAG) == 0) { if (spa_version(spa) < - ZFS_VERSION_GZIP_COMPRESSION) { + SPA_VERSION_GZIP_COMPRESSION) { spa_close(spa, FTAG); return (ENOTSUP); } @@ -1299,8 +1305,7 @@ zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl) switch (prop) { case ZFS_PROP_QUOTA: if ((error = nvpair_value_uint64(elem, &intval)) != 0 || - (error = dsl_dir_set_quota(name, - intval)) != 0) + (error = dsl_dir_set_quota(name, intval)) != 0) return (error); break; @@ -1313,15 +1318,19 @@ 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, dev, intval)) != 0) return (error); break; case ZFS_PROP_VOLBLOCKSIZE: if ((error = nvpair_value_uint64(elem, &intval)) != 0 || - (error = zvol_set_volblocksize(name, - intval)) != 0) + (error = zvol_set_volblocksize(name, intval)) != 0) + return (error); + break; + + case ZFS_PROP_VERSION: + if ((error = nvpair_value_uint64(elem, &intval)) != 0 || + (error = zfs_set_version(name, intval)) != 0) return (error); break; @@ -1355,8 +1364,8 @@ zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl) return (EINVAL); break; default: - cmn_err(CE_PANIC, "unknown property " - "type"); + cmn_err(CE_PANIC, + "unknown property type"); break; } @@ -1427,7 +1436,7 @@ zfs_ioc_pool_set_props(zfs_cmd_t *zc) return (error); } - if (spa_version(spa) < ZFS_VERSION_BOOTFS) { + if (spa_version(spa) < SPA_VERSION_BOOTFS) { nvlist_free(nvl); spa_close(spa, FTAG); return (ENOTSUP); @@ -1669,7 +1678,13 @@ zfs_get_vfs(const char *resource) static void zfs_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) { - zfs_create_fs(os, cr, tx); + nvlist_t *nvprops = arg; + uint64_t version = ZPL_VERSION; + + (void) nvlist_lookup_uint64(nvprops, + zfs_prop_to_name(ZFS_PROP_VERSION), &version); + + zfs_create_fs(os, cr, version, tx); } static int @@ -1754,6 +1769,16 @@ zfs_ioc_create(zfs_cmd_t *zc) nvlist_free(nvprops); return (error); } + } else if (type == DMU_OST_ZFS) { + uint64_t version; + + if (0 == nvlist_lookup_uint64(nvprops, + zfs_prop_to_name(ZFS_PROP_VERSION), &version) && + (version < ZPL_VERSION_INITIAL || + version > ZPL_VERSION)) { + nvlist_free(nvprops); + return (EINVAL); + } } error = dmu_objset_create(zc->zc_name, type, NULL, cbfunc, @@ -2122,54 +2147,54 @@ zfs_ioc_share(zfs_cmd_t *zc) * of those commands. */ static zfs_ioc_vec_t zfs_ioc_vec[] = { - { zfs_ioc_pool_create, zfs_secpolicy_config, pool_name, B_TRUE }, - { zfs_ioc_pool_destroy, zfs_secpolicy_config, pool_name, B_FALSE }, - { zfs_ioc_pool_import, zfs_secpolicy_config, pool_name, B_TRUE }, - { zfs_ioc_pool_export, zfs_secpolicy_config, pool_name, B_FALSE }, - { zfs_ioc_pool_configs, zfs_secpolicy_none, no_name, B_FALSE }, - { zfs_ioc_pool_stats, zfs_secpolicy_read, pool_name, B_FALSE }, - { zfs_ioc_pool_tryimport, zfs_secpolicy_config, no_name, B_FALSE }, - { zfs_ioc_pool_scrub, zfs_secpolicy_config, pool_name, B_TRUE }, - { zfs_ioc_pool_freeze, zfs_secpolicy_config, no_name, B_FALSE }, - { zfs_ioc_pool_upgrade, zfs_secpolicy_config, pool_name, B_TRUE }, - { zfs_ioc_pool_get_history, zfs_secpolicy_config, pool_name, B_FALSE }, - { zfs_ioc_vdev_add, zfs_secpolicy_config, pool_name, B_TRUE }, - { zfs_ioc_vdev_remove, zfs_secpolicy_config, pool_name, B_TRUE }, - { zfs_ioc_vdev_set_state, zfs_secpolicy_config, pool_name, B_TRUE }, - { zfs_ioc_vdev_attach, zfs_secpolicy_config, pool_name, B_TRUE }, - { zfs_ioc_vdev_detach, zfs_secpolicy_config, pool_name, B_TRUE }, - { zfs_ioc_vdev_setpath, zfs_secpolicy_config, pool_name, B_FALSE }, - { zfs_ioc_objset_stats, zfs_secpolicy_read, dataset_name, B_FALSE }, + { zfs_ioc_pool_create, zfs_secpolicy_config, POOL_NAME, B_TRUE }, + { zfs_ioc_pool_destroy, zfs_secpolicy_config, POOL_NAME, B_FALSE }, + { zfs_ioc_pool_import, zfs_secpolicy_config, POOL_NAME, B_TRUE }, + { zfs_ioc_pool_export, zfs_secpolicy_config, POOL_NAME, B_FALSE }, + { zfs_ioc_pool_configs, zfs_secpolicy_none, NO_NAME, B_FALSE }, + { zfs_ioc_pool_stats, zfs_secpolicy_read, POOL_NAME, B_FALSE }, + { zfs_ioc_pool_tryimport, zfs_secpolicy_config, NO_NAME, B_FALSE }, + { zfs_ioc_pool_scrub, zfs_secpolicy_config, POOL_NAME, B_TRUE }, + { zfs_ioc_pool_freeze, zfs_secpolicy_config, NO_NAME, B_FALSE }, + { zfs_ioc_pool_upgrade, zfs_secpolicy_config, POOL_NAME, B_TRUE }, + { zfs_ioc_pool_get_history, zfs_secpolicy_config, POOL_NAME, B_FALSE }, + { zfs_ioc_vdev_add, zfs_secpolicy_config, POOL_NAME, B_TRUE }, + { zfs_ioc_vdev_remove, zfs_secpolicy_config, POOL_NAME, B_TRUE }, + { zfs_ioc_vdev_set_state, zfs_secpolicy_config, POOL_NAME, B_TRUE }, + { zfs_ioc_vdev_attach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, + { zfs_ioc_vdev_detach, zfs_secpolicy_config, POOL_NAME, B_TRUE }, + { zfs_ioc_vdev_setpath, zfs_secpolicy_config, POOL_NAME, B_FALSE }, + { zfs_ioc_objset_stats, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, { zfs_ioc_dataset_list_next, zfs_secpolicy_read, - dataset_name, B_FALSE }, + DATASET_NAME, B_FALSE }, { zfs_ioc_snapshot_list_next, zfs_secpolicy_read, - dataset_name, B_FALSE }, - { zfs_ioc_set_prop, zfs_secpolicy_none, dataset_name, B_TRUE }, - { zfs_ioc_create_minor, zfs_secpolicy_minor, dataset_name, B_FALSE }, - { zfs_ioc_remove_minor, zfs_secpolicy_minor, dataset_name, B_FALSE }, - { zfs_ioc_create, zfs_secpolicy_create, dataset_name, B_TRUE }, - { zfs_ioc_destroy, zfs_secpolicy_destroy, dataset_name, B_TRUE }, - { zfs_ioc_rollback, zfs_secpolicy_rollback, dataset_name, B_TRUE }, - { zfs_ioc_rename, zfs_secpolicy_rename, dataset_name, B_TRUE }, - { zfs_ioc_recvbackup, zfs_secpolicy_receive, dataset_name, B_TRUE }, - { zfs_ioc_sendbackup, zfs_secpolicy_send, dataset_name, B_TRUE }, - { zfs_ioc_inject_fault, zfs_secpolicy_inject, no_name, B_FALSE }, - { zfs_ioc_clear_fault, zfs_secpolicy_inject, no_name, B_FALSE }, - { zfs_ioc_inject_list_next, zfs_secpolicy_inject, no_name, B_FALSE }, - { zfs_ioc_error_log, zfs_secpolicy_inject, pool_name, B_FALSE }, - { zfs_ioc_clear, zfs_secpolicy_config, pool_name, B_TRUE }, - { zfs_ioc_promote, zfs_secpolicy_promote, dataset_name, B_TRUE }, - { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, dataset_name, B_TRUE }, - { zfs_ioc_snapshot, zfs_secpolicy_snapshot, dataset_name, B_TRUE }, - { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, pool_name, B_FALSE }, - { zfs_ioc_obj_to_path, zfs_secpolicy_config, no_name, B_FALSE }, - { zfs_ioc_pool_set_props, zfs_secpolicy_config, pool_name, B_TRUE }, - { zfs_ioc_pool_get_props, zfs_secpolicy_read, pool_name, B_FALSE }, - { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, dataset_name, B_TRUE }, - { zfs_ioc_get_fsacl, zfs_secpolicy_read, dataset_name, B_FALSE }, + DATASET_NAME, B_FALSE }, + { zfs_ioc_set_prop, zfs_secpolicy_none, DATASET_NAME, B_TRUE }, + { zfs_ioc_create_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, + { zfs_ioc_remove_minor, zfs_secpolicy_minor, DATASET_NAME, B_FALSE }, + { zfs_ioc_create, zfs_secpolicy_create, DATASET_NAME, B_TRUE }, + { zfs_ioc_destroy, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, + { zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, B_TRUE }, + { zfs_ioc_rename, zfs_secpolicy_rename, DATASET_NAME, B_TRUE }, + { zfs_ioc_recvbackup, zfs_secpolicy_receive, DATASET_NAME, B_TRUE }, + { zfs_ioc_sendbackup, zfs_secpolicy_send, DATASET_NAME, B_TRUE }, + { zfs_ioc_inject_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, + { zfs_ioc_clear_fault, zfs_secpolicy_inject, NO_NAME, B_FALSE }, + { zfs_ioc_inject_list_next, zfs_secpolicy_inject, NO_NAME, B_FALSE }, + { zfs_ioc_error_log, zfs_secpolicy_inject, POOL_NAME, B_FALSE }, + { zfs_ioc_clear, zfs_secpolicy_config, POOL_NAME, B_TRUE }, + { zfs_ioc_promote, zfs_secpolicy_promote, DATASET_NAME, B_TRUE }, + { zfs_ioc_destroy_snaps, zfs_secpolicy_destroy, DATASET_NAME, B_TRUE }, + { zfs_ioc_snapshot, zfs_secpolicy_snapshot, DATASET_NAME, B_TRUE }, + { zfs_ioc_dsobj_to_dsname, zfs_secpolicy_config, POOL_NAME, B_FALSE }, + { zfs_ioc_obj_to_path, zfs_secpolicy_config, NO_NAME, B_FALSE }, + { zfs_ioc_pool_set_props, zfs_secpolicy_config, POOL_NAME, B_TRUE }, + { zfs_ioc_pool_get_props, zfs_secpolicy_read, POOL_NAME, B_FALSE }, + { zfs_ioc_set_fsacl, zfs_secpolicy_fsacl, DATASET_NAME, B_TRUE }, + { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE }, { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, - dataset_name, B_FALSE }, - { zfs_ioc_share, zfs_secpolicy_share, dataset_name, B_FALSE } + DATASET_NAME, B_FALSE }, + { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE } }; static int @@ -2204,17 +2229,17 @@ zfsdev_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) if (error == 0) { zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; switch (zfs_ioc_vec[vec].zvec_namecheck) { - case pool_name: + case POOL_NAME: if (pool_namecheck(zc->zc_name, NULL, NULL) != 0) error = EINVAL; break; - case dataset_name: + case DATASET_NAME: if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0) error = EINVAL; break; - case no_name: + case NO_NAME: break; } } @@ -2328,7 +2353,7 @@ static struct dev_ops zfs_dev_ops = { }; static struct modldrv zfs_modldrv = { - &mod_driverops, "ZFS storage pool version " ZFS_VERSION_STRING, + &mod_driverops, "ZFS storage pool version " SPA_VERSION_STRING, &zfs_dev_ops }; diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c index 40915bfec5..f849bf98de 100644 --- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c @@ -628,10 +628,33 @@ zfs_domount(vfs_t *vfsp, char *osname, cred_t *cr) if (error) goto out; - zfs_unlinked_drain(zfsvfs); + if (!(zfsvfs->z_vfs->vfs_flag & VFS_RDONLY)) + zfs_unlinked_drain(zfsvfs); /* * Parse and replay the intent log. + * + * Because of ziltest, this must be done after + * zfs_unlinked_drain(). (Further note: ziltest doesn't + * use readonly mounts, where zfs_unlinked_drain() isn't + * called.) This is because ziltest causes spa_sync() + * to think it's committed, but actually it is not, so + * the intent log contains many txg's worth of changes. + * + * In particular, if object N is in the unlinked set in + * the last txg to actually sync, then it could be + * actually freed in a later txg and then reallocated in + * a yet later txg. This would write a "create object + * N" record to the intent log. Normally, this would be + * fine because the spa_sync() would have written out + * the fact that object N is free, before we could write + * the "create object N" intent log record. + * + * But when we are in ziltest mode, we advance the "open + * txg" without actually spa_sync()-ing the changes to + * disk. So we would see that object N is still + * allocated and in the unlinked set, and there is an + * intent log record saying to allocate it. */ zil_replay(zfsvfs->z_os, zfsvfs, &zfsvfs->z_assign, zfs_replay_vector); @@ -652,7 +675,6 @@ out: } return (error); - } void @@ -717,7 +739,6 @@ str_to_uint64(char *str, uint64_t *objnum) return (0); } - /* * The boot path passed from the boot loader is in the form of * "rootpool-name/root-filesystem-object-number'. Convert this @@ -817,13 +838,10 @@ out: vfs_unlock(vfsp); ret = (error) ? error : 0; return (ret); - } else if (why == ROOT_REMOUNT) { - readonly_changed_cb(vfsp->vfs_data, B_FALSE); vfsp->vfs_flag |= VFS_REMOUNT; return (zfs_refresh_properties(vfsp)); - } else if (why == ROOT_UNMOUNT) { zfs_unregister_callbacks((zfsvfs_t *)vfsp->vfs_data); (void) zfs_sync(vfsp, 0, 0); @@ -873,9 +891,8 @@ zfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) * When doing a remount, we simply refresh our temporary properties * according to those options set in the current VFS options. */ - if (uap->flags & MS_REMOUNT) { + if (uap->flags & MS_REMOUNT) return (zfs_refresh_properties(vfsp)); - } /* * Get the objset name (the "special" mount argument). @@ -1347,6 +1364,70 @@ zfs_busy(void) return (zfs_active_fs_count != 0); } +int +zfs_get_stats(objset_t *os, nvlist_t *nv) +{ + int error; + uint64_t val; + + error = zap_lookup(os, MASTER_NODE_OBJ, ZPL_VERSION_STR, 8, 1, &val); + if (error == 0) + dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_VERSION, val); + + return (error); +} + +int +zfs_set_version(const char *name, uint64_t newvers) +{ + int error; + objset_t *os; + dmu_tx_t *tx; + uint64_t curvers; + + /* + * XXX for now, require that the filesystem be unmounted. Would + * be nice to find the zfsvfs_t and just update that if + * possible. + */ + + if (newvers < ZPL_VERSION_INITIAL || newvers > ZPL_VERSION) + return (EINVAL); + + error = dmu_objset_open(name, DMU_OST_ZFS, DS_MODE_PRIMARY, &os); + if (error) + return (error); + + error = zap_lookup(os, MASTER_NODE_OBJ, ZPL_VERSION_STR, + 8, 1, &curvers); + if (error) + goto out; + if (newvers < curvers) { + error = EINVAL; + goto out; + } + + tx = dmu_tx_create(os); + dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, 0, ZPL_VERSION_STR); + error = dmu_tx_assign(tx, TXG_WAIT); + if (error) { + dmu_tx_abort(tx); + goto out; + } + error = zap_update(os, MASTER_NODE_OBJ, ZPL_VERSION_STR, 8, 1, + &newvers, tx); + + spa_history_internal_log(LOG_DS_UPGRADE, + dmu_objset_spa(os), tx, CRED(), + "oldver=%llu newver=%llu dataset = %llu", curvers, newvers, + dmu_objset_id(os)); + dmu_tx_commit(tx); + +out: + dmu_objset_close(os); + return (error); +} + static vfsdef_t vfw = { VFSDEF_VERSION, MNTTYPE_ZFS, @@ -1356,5 +1437,5 @@ static vfsdef_t vfw = { }; struct modlfs zfs_modlfs = { - &mod_fsops, "ZFS filesystem version " ZFS_VERSION_STRING, &vfw + &mod_fsops, "ZFS filesystem version " SPA_VERSION_STRING, &vfw }; diff --git a/usr/src/uts/common/fs/zfs/zfs_znode.c b/usr/src/uts/common/fs/zfs/zfs_znode.c index be7522ee80..8a39bb1602 100644 --- a/usr/src/uts/common/fs/zfs/zfs_znode.c +++ b/usr/src/uts/common/fs/zfs/zfs_znode.c @@ -250,7 +250,6 @@ zfs_init_fs(zfsvfs_t *zfsvfs, znode_t **zpp, cred_t *cr) extern int zfsfstype; objset_t *os = zfsvfs->z_os; - uint64_t version = ZPL_VERSION; int i, error; dmu_object_info_t doi; uint64_t fsid_guid; @@ -269,19 +268,19 @@ zfs_init_fs(zfsvfs_t *zfsvfs, znode_t **zpp, cred_t *cr) dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); /* root node */ error = dmu_tx_assign(tx, TXG_WAIT); ASSERT3U(error, ==, 0); - zfs_create_fs(os, cr, tx); + zfs_create_fs(os, cr, ZPL_VERSION, tx); dmu_tx_commit(tx); } - error = zap_lookup(os, MASTER_NODE_OBJ, ZPL_VERSION_OBJ, 8, 1, - &version); + error = zap_lookup(os, MASTER_NODE_OBJ, ZPL_VERSION_STR, 8, 1, + &zfsvfs->z_version); if (error) { return (error); - } else if (version != ZPL_VERSION) { + } else if (zfsvfs->z_version > ZPL_VERSION) { (void) printf("Mismatched versions: File system " "is version %lld on-disk format, which is " "incompatible with this software version %lld!", - (u_longlong_t)version, ZPL_VERSION); + (u_longlong_t)zfsvfs->z_version, ZPL_VERSION); return (ENOTSUP); } @@ -1040,11 +1039,10 @@ zfs_freesp(znode_t *zp, uint64_t off, uint64_t len, int flag, boolean_t log) } void -zfs_create_fs(objset_t *os, cred_t *cr, dmu_tx_t *tx) +zfs_create_fs(objset_t *os, cred_t *cr, uint64_t version, dmu_tx_t *tx) { zfsvfs_t zfsvfs; uint64_t moid, doid, roid = 0; - uint64_t version = ZPL_VERSION; int error; znode_t *rootzp = NULL; vnode_t *vp; @@ -1066,7 +1064,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, dmu_tx_t *tx) * Set starting attributes. */ - error = zap_update(os, moid, ZPL_VERSION_OBJ, 8, 1, &version, tx); + error = zap_update(os, moid, ZPL_VERSION_STR, 8, 1, &version, tx); ASSERT(error == 0); /* @@ -1176,7 +1174,8 @@ zfs_obj_to_path(objset_t *osp, uint64_t obj, char *buf, int len) if (is_xattrdir) { (void) sprintf(component + 1, "<xattrdir>"); } else { - error = zap_value_search(osp, pobj, obj, component + 1); + error = zap_value_search(osp, pobj, obj, + ZFS_DIRENT_OBJ(-1ULL), component + 1); if (error != 0) break; } diff --git a/usr/src/uts/common/sys/fs/zfs.h b/usr/src/uts/common/sys/fs/zfs.h index 1023e31c16..5de4a0e83f 100644 --- a/usr/src/uts/common/sys/fs/zfs.h +++ b/usr/src/uts/common/sys/fs/zfs.h @@ -97,7 +97,8 @@ typedef enum { ZPOOL_PROP_BOOTFS, ZPOOL_PROP_AUTOREPLACE, ZPOOL_PROP_DELEGATION, - ZPOOL_PROP_NAME + ZFS_PROP_VERSION, + ZPOOL_PROP_NAME /* XXX must be last! */ } zfs_prop_t; typedef zfs_prop_t zpool_prop_t; @@ -172,45 +173,61 @@ extern zpool_prop_t zpool_prop_iter(zpool_prop_f, void *, boolean_t); /* * On-disk version number. */ -#define ZFS_VERSION_1 1ULL -#define ZFS_VERSION_2 2ULL -#define ZFS_VERSION_3 3ULL -#define ZFS_VERSION_4 4ULL -#define ZFS_VERSION_5 5ULL -#define ZFS_VERSION_6 6ULL -#define ZFS_VERSION_7 7ULL -#define ZFS_VERSION_8 8ULL +#define SPA_VERSION_1 1ULL +#define SPA_VERSION_2 2ULL +#define SPA_VERSION_3 3ULL +#define SPA_VERSION_4 4ULL +#define SPA_VERSION_5 5ULL +#define SPA_VERSION_6 6ULL +#define SPA_VERSION_7 7ULL +#define SPA_VERSION_8 8ULL /* - * When bumping up ZFS_VERSION, make sure GRUB ZFS understand the on-disk + * When bumping up SPA_VERSION, make sure GRUB ZFS understand the on-disk * format change. Go to usr/src/grub/grub-0.95/stage2/{zfs-include/, fsys_zfs*}, * and do the appropriate changes. */ -#define ZFS_VERSION ZFS_VERSION_8 -#define ZFS_VERSION_STRING "8" +#define SPA_VERSION SPA_VERSION_8 +#define SPA_VERSION_STRING "8" /* - * Symbolic names for the changes that caused a ZFS_VERSION switch. + * Symbolic names for the changes that caused a SPA_VERSION switch. * Used in the code when checking for presence or absence of a feature. * Feel free to define multiple symbolic names for each version if there * were multiple changes to on-disk structures during that version. * - * NOTE: When checking the current ZFS_VERSION in your code, be sure + * NOTE: When checking the current SPA_VERSION in your code, be sure * to use spa_version() since it reports the version of the * last synced uberblock. Checking the in-flight version can * be dangerous in some cases. */ -#define ZFS_VERSION_INITIAL ZFS_VERSION_1 -#define ZFS_VERSION_DITTO_BLOCKS ZFS_VERSION_2 -#define ZFS_VERSION_SPARES ZFS_VERSION_3 -#define ZFS_VERSION_RAID6 ZFS_VERSION_3 -#define ZFS_VERSION_BPLIST_ACCOUNT ZFS_VERSION_3 -#define ZFS_VERSION_RAIDZ_DEFLATE ZFS_VERSION_3 -#define ZFS_VERSION_DNODE_BYTES ZFS_VERSION_3 -#define ZFS_VERSION_ZPOOL_HISTORY ZFS_VERSION_4 -#define ZFS_VERSION_GZIP_COMPRESSION ZFS_VERSION_5 -#define ZFS_VERSION_BOOTFS ZFS_VERSION_6 -#define ZFS_VERSION_SLOGS ZFS_VERSION_7 -#define ZFS_VERSION_DELEGATED_PERMS ZFS_VERSION_8 +#define SPA_VERSION_INITIAL SPA_VERSION_1 +#define SPA_VERSION_DITTO_BLOCKS SPA_VERSION_2 +#define SPA_VERSION_SPARES SPA_VERSION_3 +#define SPA_VERSION_RAID6 SPA_VERSION_3 +#define SPA_VERSION_BPLIST_ACCOUNT SPA_VERSION_3 +#define SPA_VERSION_RAIDZ_DEFLATE SPA_VERSION_3 +#define SPA_VERSION_DNODE_BYTES SPA_VERSION_3 +#define SPA_VERSION_ZPOOL_HISTORY SPA_VERSION_4 +#define SPA_VERSION_GZIP_COMPRESSION SPA_VERSION_5 +#define SPA_VERSION_BOOTFS SPA_VERSION_6 +#define ZFS_VERSION_SLOGS SPA_VERSION_7 +#define ZFS_VERSION_DELEGATED_PERMS SPA_VERSION_8 + +/* + * ZPL version - rev'd whenever an incompatible on-disk format change + * occurs. This is independent of SPA/DMU/ZAP versioning. You must + * also update the version_table[] and help message in zfs_prop.c. + * + * When changing, be sure to teach GRUB how to read the new format! + * See usr/src/grub/grub-0.95/stage2/{zfs-include/,fsys_zfs*} + */ +#define ZPL_VERSION_1 1ULL +#define ZPL_VERSION_2 2ULL +#define ZPL_VERSION ZPL_VERSION_2 +#define ZPL_VERSION_STRING "2" + +#define ZPL_VERSION_INITIAL ZPL_VERSION_1 +#define ZPL_VERSION_DIRENT_TYPE ZPL_VERSION_2 /* * The following are configuration names used in the nvlist describing a pool's @@ -556,6 +573,7 @@ typedef enum history_internal_events { LOG_DS_REPLAY_FULL_SYNC, LOG_DS_ROLLBACK, LOG_DS_SNAPSHOT, + LOG_DS_UPGRADE, LOG_END } history_internal_events_t; |