Mercurial > illumos > illumos-gate
changeset 7265:cc18862247da
PSARC/2008/483 ZFS clone -o
PSARC/2008/484 ZFS snapshot properties
6613766 create-time properties for clones
6701797 want user properties on snapshots
line wrap: on
line diff
--- a/usr/src/cmd/zdb/zdb.c Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/cmd/zdb/zdb.c Fri Aug 01 16:32:18 2008 -0700 @@ -802,6 +802,8 @@ (u_longlong_t)ds->ds_flags); (void) printf("\t\tnext_clones_obj = %llu\n", (u_longlong_t)ds->ds_next_clones_obj); + (void) printf("\t\tprops_obj = %llu\n", + (u_longlong_t)ds->ds_props_obj); (void) printf("\t\tbp = %s\n", blkbuf); }
--- a/usr/src/cmd/zfs/zfs_main.c Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/cmd/zfs/zfs_main.c Fri Aug 01 16:32:18 2008 -0700 @@ -175,8 +175,8 @@ { switch (idx) { case HELP_CLONE: - return (gettext("\tclone [-p] <snapshot> " - "<filesystem|volume>\n")); + return (gettext("\tclone [-p] [-o property=value] ... " + "<snapshot> <filesystem|volume>\n")); case HELP_CREATE: return (gettext("\tcreate [-p] [-o property=value] ... " "<filesystem>\n" @@ -192,7 +192,7 @@ "[filesystem|volume|snapshot] ...\n")); case HELP_INHERIT: return (gettext("\tinherit [-r] <property> " - "<filesystem|volume> ...\n")); + "<filesystem|volume|snapshot> ...\n")); case HELP_UPGRADE: return (gettext("\tupgrade [-v]\n" "\tupgrade [-r] [-V version] <-a | filesystem ...>\n")); @@ -221,11 +221,11 @@ return (gettext("\tsend [-R] [-[iI] snapshot] <snapshot>\n")); case HELP_SET: return (gettext("\tset <property=value> " - "<filesystem|volume> ...\n")); + "<filesystem|volume|snapshot> ...\n")); case HELP_SHARE: return (gettext("\tshare <-a | filesystem>\n")); case HELP_SNAPSHOT: - return (gettext("\tsnapshot [-r] " + return (gettext("\tsnapshot [-r] [-o property=value] ... " "<filesystem@snapname|volume@snapname>\n")); case HELP_UNMOUNT: return (gettext("\tunmount [-f] " @@ -397,8 +397,35 @@ exit(requested ? 0 : 2); } +static int +parseprop(nvlist_t *props) +{ + char *propname = optarg; + char *propval, *strval; + + if ((propval = strchr(propname, '=')) == NULL) { + (void) fprintf(stderr, gettext("missing " + "'=' for -o option\n")); + return (-1); + } + *propval = '\0'; + propval++; + if (nvlist_lookup_string(props, propname, &strval) == 0) { + (void) fprintf(stderr, gettext("property '%s' " + "specified multiple times\n"), propname); + return (-1); + } + if (nvlist_add_string(props, propname, propval) != 0) { + (void) fprintf(stderr, gettext("internal " + "error: out of memory\n")); + return (-1); + } + return (0); + +} + /* - * zfs clone [-p] <snap> <fs | vol> + * zfs clone [-p] [-o prop=value] ... <snap> <fs | vol> * * Given an existing dataset, create a writable copy whose initial contents * are the same as the source. The newly created dataset maintains a @@ -410,21 +437,32 @@ static int zfs_do_clone(int argc, char **argv) { - zfs_handle_t *zhp; + zfs_handle_t *zhp = NULL; boolean_t parents = B_FALSE; + nvlist_t *props; int ret; int c; + if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { + (void) fprintf(stderr, gettext("internal error: " + "out of memory\n")); + return (1); + } + /* check options */ - while ((c = getopt(argc, argv, "p")) != -1) { + while ((c = getopt(argc, argv, "o:p")) != -1) { switch (c) { + case 'o': + if (parseprop(props)) + return (1); + break; case 'p': parents = B_TRUE; break; case '?': (void) fprintf(stderr, gettext("invalid option '%c'\n"), optopt); - usage(B_FALSE); + goto usage; } } @@ -435,16 +473,16 @@ if (argc < 1) { (void) fprintf(stderr, gettext("missing source dataset " "argument\n")); - usage(B_FALSE); + goto usage; } if (argc < 2) { (void) fprintf(stderr, gettext("missing target dataset " "argument\n")); - usage(B_FALSE); + goto usage; } if (argc > 2) { (void) fprintf(stderr, gettext("too many arguments\n")); - usage(B_FALSE); + goto usage; } /* open the source dataset */ @@ -466,7 +504,7 @@ } /* pass to libzfs */ - ret = zfs_clone(zhp, argv[1], NULL); + ret = zfs_clone(zhp, argv[1], props); /* create the mountpoint if necessary */ if (ret == 0) { @@ -481,8 +519,16 @@ } zfs_close(zhp); - - return (ret == 0 ? 0 : 1); + nvlist_free(props); + + return (!!ret); + +usage: + if (zhp) + zfs_close(zhp); + nvlist_free(props); + usage(B_FALSE); + return (-1); } /* @@ -511,11 +557,8 @@ boolean_t bflag = B_FALSE; boolean_t parents = B_FALSE; int ret = 1; - nvlist_t *props = NULL; + nvlist_t *props; uint64_t intval; - char *propname; - char *propval = NULL; - char *strval; int canmount; if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { @@ -566,25 +609,8 @@ } break; case 'o': - propname = optarg; - if ((propval = strchr(propname, '=')) == NULL) { - (void) fprintf(stderr, gettext("missing " - "'=' for -o option\n")); + if (parseprop(props)) goto error; - } - *propval = '\0'; - propval++; - if (nvlist_lookup_string(props, propname, - &strval) == 0) { - (void) fprintf(stderr, gettext("property '%s' " - "specified multiple times\n"), propname); - goto error; - } - if (nvlist_add_string(props, propname, propval) != 0) { - (void) fprintf(stderr, gettext("internal " - "error: out of memory\n")); - goto error; - } break; case 's': noreserve = B_TRUE; @@ -626,6 +652,7 @@ uint64_t spa_version; char *p; zfs_prop_t resv_prop; + char *strval; if (p = strchr(argv[0], '/')) *p = '\0'; @@ -1256,13 +1283,29 @@ */ static int -inherit_callback(zfs_handle_t *zhp, void *data) +inherit_recurse_cb(zfs_handle_t *zhp, void *data) { char *propname = data; int ret; - - ret = zfs_prop_inherit(zhp, propname); - return (ret != 0); + zfs_prop_t prop = zfs_name_to_prop(propname); + + /* + * If we're doing it recursively, then ignore properties that + * are not valid for this type of dataset. + */ + if (prop != ZPROP_INVAL && + !zfs_prop_valid_for_type(prop, zfs_get_type(zhp))) + return (0); + + return (zfs_prop_inherit(zhp, propname) != 0); +} + +static int +inherit_cb(zfs_handle_t *zhp, void *data) +{ + char *propname = data; + + return (zfs_prop_inherit(zhp, propname) != 0); } static int @@ -1329,9 +1372,13 @@ usage(B_FALSE); } - ret = zfs_for_each(argc, argv, recurse, - ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, NULL, NULL, - inherit_callback, propname, B_FALSE); + if (recurse) { + ret = zfs_for_each(argc, argv, recurse, ZFS_TYPE_DATASET, + NULL, NULL, inherit_recurse_cb, propname, B_FALSE); + } else { + ret = zfs_for_each(argc, argv, recurse, ZFS_TYPE_DATASET, + NULL, NULL, inherit_cb, propname, B_FALSE); + } return (ret); } @@ -2189,7 +2236,7 @@ } /* - * zfs snapshot [-r] <fs@snap> + * zfs snapshot [-r] [-o prop=value] ... <fs@snap> * * Creates a snapshot with the given name. While functionally equivalent to * 'zfs create', it is a separate command to differentiate intent. @@ -2200,17 +2247,28 @@ boolean_t recursive = B_FALSE; int ret; char c; + nvlist_t *props; + + if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { + (void) fprintf(stderr, gettext("internal error: " + "out of memory\n")); + return (1); + } /* check options */ - while ((c = getopt(argc, argv, ":r")) != -1) { + while ((c = getopt(argc, argv, "ro:")) != -1) { switch (c) { + case 'o': + if (parseprop(props)) + return (1); + break; case 'r': recursive = B_TRUE; break; case '?': (void) fprintf(stderr, gettext("invalid option '%c'\n"), optopt); - usage(B_FALSE); + goto usage; } } @@ -2220,17 +2278,23 @@ /* check number of arguments */ if (argc < 1) { (void) fprintf(stderr, gettext("missing snapshot argument\n")); - usage(B_FALSE); + goto usage; } if (argc > 1) { (void) fprintf(stderr, gettext("too many arguments\n")); - usage(B_FALSE); + goto usage; } - ret = zfs_snapshot(g_zfs, argv[0], recursive); + ret = zfs_snapshot(g_zfs, argv[0], recursive, props); + nvlist_free(props); if (ret && recursive) (void) fprintf(stderr, gettext("no snapshots were created\n")); return (ret != 0); + +usage: + nvlist_free(props); + usage(B_FALSE); + return (-1); } /*
--- a/usr/src/cmd/zoneadm/zfs.c Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/cmd/zoneadm/zfs.c Fri Aug 01 16:32:18 2008 -0700 @@ -304,7 +304,7 @@ if (pre_snapshot(presnapbuf) != Z_OK) return (Z_ERR); - res = zfs_snapshot(g_zfs, snapshot_name, B_FALSE); + res = zfs_snapshot(g_zfs, snapshot_name, B_FALSE, NULL); if (post_snapshot(postsnapbuf) != Z_OK) return (Z_ERR);
--- a/usr/src/cmd/zpool/zpool_main.c Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/cmd/zpool/zpool_main.c Fri Aug 01 16:32:18 2008 -0700 @@ -3462,6 +3462,7 @@ "properties\n")); (void) printf(gettext(" 10 Cache devices\n")); (void) printf(gettext(" 11 Improved scrub performance\n")); + (void) printf(gettext(" 12 Snapshot properties\n")); (void) printf(gettext("For more information on a particular " "version, including supported releases, see:\n\n")); (void) printf("http://www.opensolaris.org/os/community/zfs/"
--- a/usr/src/grub/grub-0.95/stage2/fsys_zfs.c Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/grub/grub-0.95/stage2/fsys_zfs.c Fri Aug 01 16:32:18 2008 -0700 @@ -269,8 +269,7 @@ return (-1); if (uber->ub_magic == UBERBLOCK_MAGIC && - uber->ub_version >= SPA_VERSION_1 && - uber->ub_version <= SPA_VERSION) + uber->ub_version > 0 && uber->ub_version <= SPA_VERSION) return (0); return (-1);
--- a/usr/src/grub/grub-0.95/stage2/zfs-include/zfs.h Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/grub/grub-0.95/stage2/zfs-include/zfs.h Fri Aug 01 16:32:18 2008 -0700 @@ -29,18 +29,7 @@ /* * On-disk version number. */ -#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_9 9ULL -#define SPA_VERSION_10 10ULL -#define SPA_VERSION_11 11ULL -#define SPA_VERSION SPA_VERSION_11 +#define SPA_VERSION 12ULL /* * The following are configuration names used in the nvlist describing a pool's
--- a/usr/src/lib/libzfs/common/libzfs.h Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/lib/libzfs/common/libzfs.h Fri Aug 01 16:32:18 2008 -0700 @@ -431,7 +431,7 @@ extern int zfs_destroy(zfs_handle_t *); extern int zfs_destroy_snaps(zfs_handle_t *, char *); extern int zfs_clone(zfs_handle_t *, const char *, nvlist_t *); -extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t); +extern int zfs_snapshot(libzfs_handle_t *, const char *, boolean_t, nvlist_t *); extern int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t); extern int zfs_rename(zfs_handle_t *, const char *, boolean_t); extern int zfs_send(zfs_handle_t *, const char *, const char *,
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c Fri Aug 01 16:32:18 2008 -0700 @@ -578,13 +578,6 @@ int chosen_normal = -1; int chosen_utf = -1; - if (type == ZFS_TYPE_SNAPSHOT) { - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "snapshot properties cannot be modified")); - (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); - return (NULL); - } - if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { (void) no_memory(hdl); return (NULL); @@ -632,6 +625,13 @@ continue; } + if (type == ZFS_TYPE_SNAPSHOT) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "this property can not be modified for snapshots")); + (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf); + goto error; + } + if (!zfs_prop_valid_for_type(prop, type)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' does not " @@ -3450,10 +3450,11 @@ * Takes a snapshot of the given dataset. */ int -zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive) +zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive, + nvlist_t *props) { const char *delim; - char *parent; + char parent[ZFS_MAXNAMELEN]; zfs_handle_t *zhp; zfs_cmd_t zc = { 0 }; int ret; @@ -3466,16 +3467,27 @@ if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE)) return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf)); + if (props) { + if ((props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT, + props, B_FALSE, NULL, errbuf)) == NULL) + return (-1); + + if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) { + nvlist_free(props); + return (-1); + } + + nvlist_free(props); + } + /* make sure the parent exists and is of the appropriate type */ delim = strchr(path, '@'); - if ((parent = zfs_alloc(hdl, delim - path + 1)) == NULL) - return (-1); (void) strncpy(parent, path, delim - path); parent[delim - path] = '\0'; if ((zhp = zfs_open(hdl, parent, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) { - free(parent); + zcmd_free_nvlists(&zc); return (-1); } @@ -3488,6 +3500,8 @@ zc.zc_cookie = recursive; ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SNAPSHOT, &zc); + zcmd_free_nvlists(&zc); + /* * if it was recursive, the one that actually failed will be in * zc.zc_name. @@ -3510,7 +3524,6 @@ dgettext(TEXT_DOMAIN, "Volume successfully snapshotted, but device links " "were not created")); - free(parent); zfs_close(zhp); return (-1); } @@ -3519,7 +3532,6 @@ if (ret != 0) (void) zfs_standard_error(hdl, errno, errbuf); - free(parent); zfs_close(zhp); return (ret);
--- a/usr/src/lib/libzfs/common/libzfs_sendrecv.c Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/lib/libzfs/common/libzfs_sendrecv.c Fri Aug 01 16:32:18 2008 -0700 @@ -166,6 +166,7 @@ uint64_t parent_fromsnap_guid; nvlist_t *parent_snaps; nvlist_t *fss; + nvlist_t *snapprops; const char *fromsnap; const char *tosnap; @@ -182,6 +183,7 @@ * * "props" -> { name -> value (only if set here) } * "snaps" -> { name (lastname) -> number (guid) } + * "snapprops" -> { name (lastname) -> { name -> value } } * * "origin" -> number (guid) (if clone) * "sent" -> boolean (not on-disk) @@ -192,12 +194,15 @@ */ } send_data_t; +static void send_iterate_prop(zfs_handle_t *zhp, nvlist_t *nv); + static int send_iterate_snap(zfs_handle_t *zhp, void *arg) { send_data_t *sd = arg; uint64_t guid = zhp->zfs_dmustats.dds_guid; char *snapname; + nvlist_t *nv; snapname = strrchr(zhp->zfs_name, '@')+1; @@ -212,6 +217,11 @@ sd->parent_fromsnap_guid = guid; } + VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0)); + send_iterate_prop(zhp, nv); + VERIFY(0 == nvlist_add_nvlist(sd->snapprops, snapname, nv)); + nvlist_free(nv); + zfs_close(zhp); return (0); } @@ -235,6 +245,8 @@ uint64_t value; verify(nvlist_lookup_uint64(propnv, ZPROP_VALUE, &value) == 0); + if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) + continue; } else { char *source; if (nvlist_lookup_string(propnv, @@ -292,9 +304,12 @@ /* iterate over snaps, and set sd->parent_fromsnap_guid */ sd->parent_fromsnap_guid = 0; VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0)); + VERIFY(0 == nvlist_alloc(&sd->snapprops, NV_UNIQUE_NAME, 0)); (void) zfs_iter_snapshots(zhp, send_iterate_snap, sd); VERIFY(0 == nvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps)); + VERIFY(0 == nvlist_add_nvlist(nvfs, "snapprops", sd->snapprops)); nvlist_free(sd->parent_snaps); + nvlist_free(sd->snapprops); /* add this fs to nvlist */ (void) snprintf(guidstring, sizeof (guidstring), @@ -1180,7 +1195,7 @@ snapelem; snapelem = nextsnapelem) { uint64_t thisguid; char *stream_snapname; - nvlist_t *found; + nvlist_t *found, *props; nextsnapelem = nvlist_next_nvpair(snaps, snapelem); @@ -1209,6 +1224,22 @@ stream_nvfs = found; + if (0 == nvlist_lookup_nvlist(stream_nvfs, "snapprops", + &props) && 0 == nvlist_lookup_nvlist(props, + stream_snapname, &props)) { + zfs_cmd_t zc = { 0 }; + + zc.zc_cookie = B_TRUE; /* clear current props */ + snprintf(zc.zc_name, sizeof (zc.zc_name), + "%s@%s", fsname, nvpair_name(snapelem)); + if (zcmd_write_src_nvlist(hdl, &zc, + props) == 0) { + (void) zfs_ioctl(hdl, + ZFS_IOC_SET_PROP, &zc); + zcmd_free_nvlists(&zc); + } + } + /* check for different snapname */ if (strcmp(nvpair_name(snapelem), stream_snapname) != 0) { @@ -1530,6 +1561,7 @@ boolean_t stream_wantsnewfs; uint64_t parent_snapguid = 0; prop_changelist_t *clp = NULL; + nvlist_t *snapprops_nvlist = NULL; begin_time = time(NULL); @@ -1537,7 +1569,9 @@ "cannot receive")); if (stream_avl != NULL) { - nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid, NULL); + char *snapname; + nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid, + &snapname); nvlist_t *props; int ret; @@ -1555,6 +1589,11 @@ if (err) nvlist_free(props); + if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) { + VERIFY(0 == nvlist_lookup_nvlist(props, + snapname, &snapprops_nvlist)); + } + if (ret != 0) return (-1); } @@ -1787,6 +1826,18 @@ err = ioctl_err = zfs_ioctl(hdl, ZFS_IOC_RECV, &zc); ioctl_errno = errno; + zcmd_free_nvlists(&zc); + + if (err == 0 && snapprops_nvlist) { + zfs_cmd_t zc2 = { 0 }; + + strcpy(zc2.zc_name, zc.zc_value); + if (zcmd_write_src_nvlist(hdl, &zc2, snapprops_nvlist) == 0) { + (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc2); + zcmd_free_nvlists(&zc2); + } + } + if (err && (ioctl_errno == ENOENT || ioctl_errno == ENODEV)) { /* * It may be that this snapshot already exists, @@ -1822,7 +1873,6 @@ *cp = '@'; } - zcmd_free_nvlists(&zc); if (ioctl_err != 0) { switch (ioctl_errno) {
--- a/usr/src/uts/common/fs/zfs/arc.c Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/arc.c Fri Aug 01 16:32:18 2008 -0700 @@ -2417,6 +2417,7 @@ uint32_t *arc_flags, const zbookmark_t *zb) { int err; + arc_buf_hdr_t *hdr = pbuf->b_hdr; ASSERT(!refcount_is_zero(&pbuf->b_hdr->b_refcnt)); ASSERT3U((char *)bp - (char *)pbuf->b_data, <, pbuf->b_hdr->b_size); @@ -2425,6 +2426,7 @@ err = arc_read_nolock(pio, spa, bp, done, private, priority, zio_flags, arc_flags, zb); + ASSERT3P(hdr, ==, pbuf->b_hdr); rw_exit(&pbuf->b_hdr->b_datalock); return (err); }
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c Fri Aug 01 16:32:18 2008 -0700 @@ -397,11 +397,11 @@ if (need_lock) rw_enter(&dp->dp_config_rwlock, RW_READER); - err = dsl_prop_get_ds_locked(ds->ds_dir, + err = dsl_prop_get_ds(ds, "refreservation", sizeof (uint64_t), 1, &ds->ds_reserved, NULL); if (err == 0) { - err = dsl_prop_get_ds_locked(ds->ds_dir, + err = dsl_prop_get_ds(ds, "refquota", sizeof (uint64_t), 1, &ds->ds_quota, NULL); } @@ -1674,6 +1674,10 @@ VERIFY(0 == dmu_object_free(mos, ds->ds_phys->ds_next_clones_obj, tx)); } + if (ds->ds_phys->ds_props_obj != 0) { + VERIFY(0 == zap_destroy(mos, + ds->ds_phys->ds_props_obj, tx)); + } dsl_dir_close(ds->ds_dir, ds); ds->ds_dir = NULL; dsl_dataset_drain_refs(ds, tag);
--- a/usr/src/uts/common/fs/zfs/dsl_deleg.c Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/dsl_deleg.c Fri Aug 01 16:32:18 2008 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -533,42 +533,33 @@ * Check if user has requested permission. */ int -dsl_deleg_access(const char *ddname, const char *perm, cred_t *cr) +dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr) { - dsl_dir_t *dd, *startdd; + dsl_dataset_t *ds; + dsl_dir_t *dd; dsl_pool_t *dp; void *cookie; int error; char checkflag = ZFS_DELEG_LOCAL; - const char *tail; objset_t *mos; avl_tree_t permsets; perm_set_t *setnode; - /* - * Use tail so that zfs_ioctl() code doesn't have - * to always to to figure out parent name in order - * to do access check. for example renaming a snapshot - */ - error = dsl_dir_open(ddname, FTAG, &startdd, &tail); + error = dsl_dataset_hold(dsname, FTAG, &ds); if (error) return (error); - if (tail && tail[0] != '@') { - dsl_dir_close(startdd, FTAG); - return (ENOENT); - } - dp = startdd->dd_pool; + dp = ds->ds_dir->dd_pool; mos = dp->dp_meta_objset; if (dsl_delegation_on(mos) == B_FALSE) { - dsl_dir_close(startdd, FTAG); + dsl_dataset_rele(ds, FTAG); return (ECANCELED); } if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) < SPA_VERSION_DELEGATED_PERMS) { - dsl_dir_close(startdd, FTAG); + dsl_dataset_rele(ds, FTAG); return (EPERM); } @@ -576,7 +567,7 @@ offsetof(perm_set_t, p_node)); rw_enter(&dp->dp_config_rwlock, RW_READER); - for (dd = startdd; dd != NULL; dd = dd->dd_parent, + for (dd = ds->ds_dir; dd != NULL; dd = dd->dd_parent, checkflag = ZFS_DELEG_DESCENDENT) { uint64_t zapobj; boolean_t expanded; @@ -588,7 +579,7 @@ if (!INGLOBALZONE(curproc)) { uint64_t zoned; - if (dsl_prop_get_ds_locked(dd, + if (dsl_prop_get_dd(dd, zfs_prop_to_name(ZFS_PROP_ZONED), 8, 1, &zoned, NULL) != 0) break; @@ -637,7 +628,7 @@ error = EPERM; success: rw_exit(&dp->dp_config_rwlock); - dsl_dir_close(startdd, FTAG); + dsl_dataset_rele(ds, FTAG); cookie = NULL; while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL)
--- a/usr/src/uts/common/fs/zfs/dsl_prop.c Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/dsl_prop.c Fri Aug 01 16:32:18 2008 -0700 @@ -68,13 +68,16 @@ return (0); } -static int -dsl_prop_get_impl(dsl_dir_t *dd, const char *propname, +int +dsl_prop_get_dd(dsl_dir_t *dd, const char *propname, int intsz, int numint, void *buf, char *setpoint) { int err = ENOENT; + objset_t *mos = dd->dd_pool->dp_meta_objset; zfs_prop_t prop; + ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); + if (setpoint) setpoint[0] = '\0'; @@ -85,7 +88,6 @@ * ouside this loop. */ for (; dd != NULL; dd = dd->dd_parent) { - objset_t *mos = dd->dd_pool->dp_meta_objset; ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname, intsz, numint, buf); @@ -107,6 +109,26 @@ return (err); } +int +dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname, + int intsz, int numint, void *buf, char *setpoint) +{ + ASSERT(RW_LOCK_HELD(&ds->ds_dir->dd_pool->dp_config_rwlock)); + + if (ds->ds_phys->ds_props_obj) { + int err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, + ds->ds_phys->ds_props_obj, propname, intsz, numint, buf); + if (err != ENOENT) { + if (setpoint) + dsl_dataset_name(ds, setpoint); + return (err); + } + } + + return (dsl_prop_get_dd(ds->ds_dir, propname, + intsz, numint, buf, setpoint)); +} + /* * Register interest in the named property. We'll call the callback * once to notify it of the current property value, and again each time @@ -119,19 +141,20 @@ dsl_prop_changed_cb_t *callback, void *cbarg) { dsl_dir_t *dd = ds->ds_dir; + dsl_pool_t *dp = dd->dd_pool; uint64_t value; dsl_prop_cb_record_t *cbr; int err; int need_rwlock; - need_rwlock = !RW_WRITE_HELD(&dd->dd_pool->dp_config_rwlock); + need_rwlock = !RW_WRITE_HELD(&dp->dp_config_rwlock); if (need_rwlock) - rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); + rw_enter(&dp->dp_config_rwlock, RW_READER); - err = dsl_prop_get_impl(dd, propname, 8, 1, &value, NULL); + err = dsl_prop_get_ds(ds, propname, 8, 1, &value, NULL); if (err != 0) { if (need_rwlock) - rw_exit(&dd->dd_pool->dp_config_rwlock); + rw_exit(&dp->dp_config_rwlock); return (err); } @@ -147,56 +170,30 @@ cbr->cbr_func(cbr->cbr_arg, value); - VERIFY(0 == dsl_dir_open_obj(dd->dd_pool, dd->dd_object, + VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, NULL, cbr, &dd)); if (need_rwlock) - rw_exit(&dd->dd_pool->dp_config_rwlock); - /* Leave dataset open until this callback is unregistered */ + rw_exit(&dp->dp_config_rwlock); + /* Leave dir open until this callback is unregistered */ return (0); } int -dsl_prop_get_dd(dsl_dir_t *dd, const char *propname, - int intsz, int numints, void *buf, char *setpoint) -{ - int err; - - rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); - err = dsl_prop_get_impl(dd, propname, intsz, numints, buf, setpoint); - rw_exit(&dd->dd_pool->dp_config_rwlock); - - return (err); -} - -/* - * Get property when config lock is already held. - */ -int dsl_prop_get_ds_locked(dsl_dir_t *dd, const char *propname, +dsl_prop_get(const char *dsname, const char *propname, int intsz, int numints, void *buf, char *setpoint) { - ASSERT(RW_LOCK_HELD(&dd->dd_pool->dp_config_rwlock)); - return (dsl_prop_get_impl(dd, propname, intsz, numints, buf, setpoint)); -} - -int -dsl_prop_get(const char *ddname, const char *propname, - int intsz, int numints, void *buf, char *setpoint) -{ - dsl_dir_t *dd; - const char *tail; + dsl_dataset_t *ds; int err; - err = dsl_dir_open(ddname, FTAG, &dd, &tail); + err = dsl_dataset_hold(dsname, FTAG, &ds); if (err) return (err); - if (tail && tail[0] != '@') { - dsl_dir_close(dd, FTAG); - return (ENOENT); - } - err = dsl_prop_get_dd(dd, propname, intsz, numints, buf, setpoint); + rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); + err = dsl_prop_get_ds(ds, propname, intsz, numints, buf, setpoint); + rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); - dsl_dir_close(dd, FTAG); + dsl_dataset_rele(ds, FTAG); return (err); } @@ -282,6 +279,7 @@ zap_cursor_t zc; zap_attribute_t *za; int err; + uint64_t dummyval; ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); err = dsl_dir_open_obj(dp, ddobj, NULL, FTAG, &dd); @@ -294,7 +292,7 @@ * being inherited here or below; stop the recursion. */ err = zap_lookup(mos, dd->dd_phys->dd_props_zapobj, propname, - 8, 1, &value); + 8, 1, &dummyval); if (err == 0) { dsl_dir_close(dd, FTAG); return; @@ -303,11 +301,22 @@ } mutex_enter(&dd->dd_lock); - for (cbr = list_head(&dd->dd_prop_cbs); - cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) { - if (strcmp(cbr->cbr_propname, propname) == 0) { - cbr->cbr_func(cbr->cbr_arg, value); - } + for (cbr = list_head(&dd->dd_prop_cbs); cbr; + cbr = list_next(&dd->dd_prop_cbs, cbr)) { + uint64_t propobj = cbr->cbr_ds->ds_phys->ds_props_obj; + + if (strcmp(cbr->cbr_propname, propname) != 0) + continue; + + /* + * If the property is set on this ds, then it is not + * inherited here; don't call the callback. + */ + if (propobj && 0 == zap_lookup(mos, propobj, propname, + 8, 1, &dummyval)) + continue; + + cbr->cbr_func(cbr->cbr_arg, value); } mutex_exit(&dd->dd_lock); @@ -335,22 +344,35 @@ static void dsl_prop_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) { - dsl_dir_t *dd = arg1; + dsl_dataset_t *ds = arg1; struct prop_set_arg *psa = arg2; - objset_t *mos = dd->dd_pool->dp_meta_objset; - uint64_t zapobj = dd->dd_phys->dd_props_zapobj; - uint64_t intval; + objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; + uint64_t zapobj, intval; int isint; char valbuf[32]; char *valstr; isint = (dodefault(psa->name, 8, 1, &intval) == 0); + if (dsl_dataset_is_snapshot(ds)) { + ASSERT(spa_version(ds->ds_dir->dd_pool->dp_spa) >= + SPA_VERSION_SNAP_PROPS); + if (ds->ds_phys->ds_props_obj == 0) { + dmu_buf_will_dirty(ds->ds_dbuf, tx); + ds->ds_phys->ds_props_obj = + zap_create(mos, + DMU_OT_DSL_PROPS, DMU_OT_NONE, 0, tx); + } + zapobj = ds->ds_phys->ds_props_obj; + } else { + zapobj = ds->ds_dir->dd_phys->dd_props_zapobj; + } + if (psa->numints == 0) { int err = zap_remove(mos, zapobj, psa->name, tx); ASSERT(err == 0 || err == ENOENT); if (isint) { - VERIFY(0 == dsl_prop_get_impl(dd->dd_parent, + VERIFY(0 == dsl_prop_get_ds(ds, psa->name, 8, 1, &intval, NULL)); } } else { @@ -361,8 +383,25 @@ } if (isint) { - dsl_prop_changed_notify(dd->dd_pool, - dd->dd_object, psa->name, intval, TRUE); + if (dsl_dataset_is_snapshot(ds)) { + dsl_prop_cb_record_t *cbr; + /* + * It's a snapshot; nothing can inherit this + * property, so just look for callbacks on this + * ds here. + */ + mutex_enter(&ds->ds_dir->dd_lock); + for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr; + cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) { + if (cbr->cbr_ds == ds && + strcmp(cbr->cbr_propname, psa->name) == 0) + cbr->cbr_func(cbr->cbr_arg, intval); + } + mutex_exit(&ds->ds_dir->dd_lock); + } else { + dsl_prop_changed_notify(ds->ds_dir->dd_pool, + ds->ds_dir->dd_object, psa->name, intval, TRUE); + } } if (isint) { (void) snprintf(valbuf, sizeof (valbuf), @@ -372,9 +411,8 @@ valstr = (char *)psa->buf; } spa_history_internal_log((psa->numints == 0) ? LOG_DS_INHERIT : - LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx, cr, - "%s=%s dataset = %llu", psa->name, valstr, - dd->dd_phys->dd_head_dataset_obj); + LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx, cr, + "%s=%s dataset = %llu", psa->name, valstr, ds->ds_object); } void @@ -396,27 +434,13 @@ } int -dsl_prop_set_dd(dsl_dir_t *dd, const char *propname, +dsl_prop_set(const char *dsname, const char *propname, int intsz, int numints, const void *buf) { + dsl_dataset_t *ds; + int err; struct prop_set_arg psa; - psa.name = propname; - psa.intsz = intsz; - psa.numints = numints; - psa.buf = buf; - - return (dsl_sync_task_do(dd->dd_pool, - NULL, dsl_prop_set_sync, dd, &psa, 2)); -} - -int -dsl_prop_set(const char *ddname, const char *propname, - int intsz, int numints, const void *buf) -{ - dsl_dir_t *dd; - int err; - /* * We must do these checks before we get to the syncfunc, since * it can't fail. @@ -426,11 +450,24 @@ if (intsz * numints >= ZAP_MAXVALUELEN) return (E2BIG); - err = dsl_dir_open(ddname, FTAG, &dd, NULL); + err = dsl_dataset_hold(dsname, FTAG, &ds); if (err) return (err); - err = dsl_prop_set_dd(dd, propname, intsz, numints, buf); - dsl_dir_close(dd, FTAG); + + if (dsl_dataset_is_snapshot(ds) && + spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_SNAP_PROPS) { + dsl_dataset_rele(ds, FTAG); + return (ENOTSUP); + } + + psa.name = propname; + psa.intsz = intsz; + psa.numints = numints; + psa.buf = buf; + err = dsl_sync_task_do(ds->ds_dir->dd_pool, + NULL, dsl_prop_set_sync, ds, &psa, 2); + + dsl_dataset_rele(ds, FTAG); return (err); } @@ -442,43 +479,51 @@ { dsl_dataset_t *ds = os->os->os_dsl_dataset; dsl_dir_t *dd = ds->ds_dir; - boolean_t snapshot; + boolean_t snapshot = dsl_dataset_is_snapshot(ds); int err = 0; - dsl_pool_t *dp; - objset_t *mos; - - snapshot = dsl_dataset_is_snapshot(ds); + dsl_pool_t *dp = dd->dd_pool; + objset_t *mos = dp->dp_meta_objset; + uint64_t propobj = ds->ds_phys->ds_props_obj; VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); - dp = dd->dd_pool; - mos = dp->dp_meta_objset; + if (local && snapshot && !propobj) + return (0); rw_enter(&dp->dp_config_rwlock, RW_READER); - for (; dd != NULL; dd = dd->dd_parent) { + while (dd != NULL) { char setpoint[MAXNAMELEN]; zap_cursor_t zc; zap_attribute_t za; + dsl_dir_t *dd_next; - dsl_dir_name(dd, setpoint); + if (propobj) { + dsl_dataset_name(ds, setpoint); + dd_next = dd; + } else { + dsl_dir_name(dd, setpoint); + propobj = dd->dd_phys->dd_props_zapobj; + dd_next = dd->dd_parent; + } - for (zap_cursor_init(&zc, mos, dd->dd_phys->dd_props_zapobj); + for (zap_cursor_init(&zc, mos, propobj); (err = zap_cursor_retrieve(&zc, &za)) == 0; zap_cursor_advance(&zc)) { nvlist_t *propval; - zfs_prop_t prop; - /* - * Skip non-inheritable properties. - */ - if ((prop = zfs_name_to_prop(za.za_name)) != - ZPROP_INVAL && !zfs_prop_inheritable(prop) && - dd != ds->ds_dir) + zfs_prop_t prop = zfs_name_to_prop(za.za_name); + + /* Skip non-inheritable properties. */ + if (prop != ZPROP_INVAL && + !zfs_prop_inheritable(prop) && + (dd != ds->ds_dir || (snapshot && dd != dd_next))) continue; - if (snapshot && + /* Skip properties not valid for this type. */ + if (snapshot && prop != ZPROP_INVAL && !zfs_prop_valid_for_type(prop, ZFS_TYPE_SNAPSHOT)) continue; + /* Skip properties already defined */ if (nvlist_lookup_nvlist(*nvp, za.za_name, &propval) == 0) continue; @@ -491,10 +536,8 @@ */ char *tmp = kmem_alloc(za.za_num_integers, KM_SLEEP); - err = zap_lookup(mos, - dd->dd_phys->dd_props_zapobj, - za.za_name, 1, za.za_num_integers, - tmp); + err = zap_lookup(mos, propobj, + za.za_name, 1, za.za_num_integers, tmp); if (err != 0) { kmem_free(tmp, za.za_num_integers); break; @@ -528,6 +571,8 @@ */ if (local) break; + dd = dd_next; + propobj = 0; } rw_exit(&dp->dp_config_rwlock);
--- a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h Fri Aug 01 16:32:18 2008 -0700 @@ -93,8 +93,9 @@ uint64_t ds_guid; uint64_t ds_flags; /* DS_FLAG_* */ blkptr_t ds_bp; - uint64_t ds_next_clones_obj; /* DMU_OT_DSL_NEXT_CLONES */ - uint64_t ds_pad[7]; /* pad out to 320 bytes for good measure */ + uint64_t ds_next_clones_obj; /* DMU_OT_DSL_CLONES */ + uint64_t ds_props_obj; /* DMU_OT_DSL_PROPS for snaps */ + uint64_t ds_pad[6]; /* pad out to 320 bytes for good measure */ } dsl_dataset_phys_t; typedef struct dsl_dataset {
--- a/usr/src/uts/common/fs/zfs/sys/dsl_prop.h Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/sys/dsl_prop.h Fri Aug 01 16:32:18 2008 -0700 @@ -37,6 +37,7 @@ #endif struct dsl_dataset; +struct dsl_dir; /* The callback func may not call into the DMU or DSL! */ typedef void (dsl_prop_changed_cb_t)(void *arg, uint64_t newval); @@ -55,20 +56,18 @@ dsl_prop_changed_cb_t *callback, void *cbarg); int dsl_prop_numcb(struct dsl_dataset *ds); -int dsl_prop_get_dd(dsl_dir_t *dd, const char *propname, - int intsz, int numints, void *buf, char *setpoint); int dsl_prop_get(const char *ddname, const char *propname, int intsz, int numints, void *buf, char *setpoint); int dsl_prop_get_integer(const char *ddname, const char *propname, uint64_t *valuep, char *setpoint); int dsl_prop_get_all(objset_t *os, nvlist_t **nvp, boolean_t local); -int dsl_prop_get_ds_locked(dsl_dir_t *dd, const char *propname, +int dsl_prop_get_ds(struct dsl_dataset *ds, const char *propname, + int intsz, int numints, void *buf, char *setpoint); +int dsl_prop_get_dd(struct dsl_dir *dd, const char *propname, int intsz, int numints, void *buf, char *setpoint); int dsl_prop_set(const char *ddname, const char *propname, int intsz, int numints, const void *buf); -int dsl_prop_set_dd(dsl_dir_t *dd, const char *propname, - int intsz, int numints, const void *buf); void dsl_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val, cred_t *cr, dmu_tx_t *tx);
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c Fri Aug 01 16:32:18 2008 -0700 @@ -92,6 +92,7 @@ boolean_t zvec_his_log; } zfs_ioc_vec_t; +static void clear_props(char *dataset, nvlist_t *props); static int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *, boolean_t *); int zfs_set_prop_nvlist(const char *, nvlist_t *); @@ -1465,8 +1466,6 @@ return (ENOTSUP); break; } - if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0) - return (error); } elem = NULL; @@ -1579,6 +1578,7 @@ * zc_name name of filesystem * zc_value name of property to inherit * zc_nvlist_src{_size} nvlist of properties to apply + * zc_cookie clear existing local props? * * outputs: none */ @@ -1592,6 +1592,21 @@ &nvl)) != 0) return (error); + if (zc->zc_cookie) { + nvlist_t *origprops; + objset_t *os; + + if (dmu_objset_open(zc->zc_name, DMU_OST_ANY, + DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { + if (dsl_prop_get_all(os, &origprops, TRUE) == 0) { + clear_props(zc->zc_name, origprops); + nvlist_free(origprops); + } + dmu_objset_close(os); + } + + } + error = zfs_set_prop_nvlist(zc->zc_name, nvl); nvlist_free(nvl); @@ -2129,6 +2144,27 @@ return (error); } +struct snap_prop_arg { + nvlist_t *nvprops; + const char *snapname; +}; + +static int +set_snap_props(char *name, void *arg) +{ + struct snap_prop_arg *snpa = arg; + int len = strlen(name) + strlen(snpa->snapname) + 2; + char *buf = kmem_alloc(len, KM_SLEEP); + int err; + + (void) snprintf(buf, len, "%s@%s", name, snpa->snapname); + err = zfs_set_prop_nvlist(buf, snpa->nvprops); + if (err) + (void) dmu_objset_destroy(buf); + kmem_free(buf, len); + return (err); +} + /* * inputs: * zc_name name of filesystem @@ -2140,10 +2176,40 @@ static int zfs_ioc_snapshot(zfs_cmd_t *zc) { + nvlist_t *nvprops = NULL; + int error; + boolean_t recursive = zc->zc_cookie; + if (snapshot_namecheck(zc->zc_value, NULL, NULL) != 0) return (EINVAL); - return (dmu_objset_snapshot(zc->zc_name, - zc->zc_value, zc->zc_cookie)); + + if (zc->zc_nvlist_src != NULL && + (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, + &nvprops)) != 0) + return (error); + + error = dmu_objset_snapshot(zc->zc_name, zc->zc_value, recursive); + + /* + * It would be nice to do this atomically. + */ + if (error == 0) { + struct snap_prop_arg snpa; + snpa.nvprops = nvprops; + snpa.snapname = zc->zc_value; + if (recursive) { + error = dmu_objset_find(zc->zc_name, + set_snap_props, &snpa, DS_FIND_CHILDREN); + if (error) { + (void) dmu_snapshots_destroy(zc->zc_name, + zc->zc_value); + } + } else { + error = set_snap_props(zc->zc_name, &snpa); + } + } + nvlist_free(nvprops); + return (error); } int
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c Fri Aug 01 16:32:18 2008 -0700 @@ -477,8 +477,9 @@ dmu_objset_name(os, osname); if (error = dsl_prop_get_integer(osname, "nbmand", &nbmand, - NULL)) - return (error); + NULL)) { + return (error); + } } /*
--- a/usr/src/uts/common/fs/zfs/zvol.c Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/uts/common/fs/zfs/zvol.c Fri Aug 01 16:32:18 2008 -0700 @@ -843,7 +843,11 @@ error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, volsize, DMU_OBJECT_END); - if (error == 0) { + /* + * If we are using a faked-up state (zv_minor == 0) then don't + * try to update the in-core zvol state. + */ + if (error == 0 && zv->zv_minor) { zv->zv_volsize = volsize; zvol_size_changed(zv, maj); } @@ -857,25 +861,31 @@ int error; dmu_object_info_t doi; uint64_t old_volsize = 0ULL; + zvol_state_t state = { 0 }; mutex_enter(&zvol_state_lock); if ((zv = zvol_minor_lookup(name)) == NULL) { - mutex_exit(&zvol_state_lock); - return (ENXIO); + /* + * If we are doing a "zfs clone -o volsize=", then the + * minor node won't exist yet. + */ + error = dmu_objset_open(name, DMU_OST_ZVOL, DS_MODE_OWNER, + &state.zv_objset); + if (error != 0) + goto out; + zv = &state; } old_volsize = zv->zv_volsize; if ((error = dmu_object_info(zv->zv_objset, ZVOL_OBJ, &doi)) != 0 || (error = zvol_check_volsize(volsize, - doi.doi_data_block_size)) != 0) { - mutex_exit(&zvol_state_lock); - return (error); - } + doi.doi_data_block_size)) != 0) + goto out; if (zv->zv_flags & ZVOL_RDONLY || (zv->zv_mode & DS_MODE_READONLY)) { - mutex_exit(&zvol_state_lock); - return (EROFS); + error = EROFS; + goto out; } error = zvol_update_volsize(zv, maj, volsize); @@ -893,6 +903,10 @@ } } +out: + if (state.zv_objset) + dmu_objset_close(state.zv_objset); + mutex_exit(&zvol_state_lock); return (error);
--- a/usr/src/uts/common/sys/fs/zfs.h Fri Aug 01 16:15:10 2008 -0700 +++ b/usr/src/uts/common/sys/fs/zfs.h Fri Aug 01 16:32:18 2008 -0700 @@ -244,13 +244,14 @@ #define SPA_VERSION_9 9ULL #define SPA_VERSION_10 10ULL #define SPA_VERSION_11 11ULL +#define SPA_VERSION_12 12ULL /* * When bumping up SPA_VERSION, make sure GRUB ZFS understands the on-disk * format change. Go to usr/src/grub/grub-0.95/stage2/{zfs-include/, fsys_zfs*}, * and do the appropriate changes. */ -#define SPA_VERSION SPA_VERSION_11 -#define SPA_VERSION_STRING "11" +#define SPA_VERSION SPA_VERSION_12 +#define SPA_VERSION_STRING "12" /* * Symbolic names for the changes that caused a SPA_VERSION switch. @@ -283,6 +284,7 @@ #define SPA_VERSION_NEXT_CLONES SPA_VERSION_11 #define SPA_VERSION_ORIGIN SPA_VERSION_11 #define SPA_VERSION_DSL_SCRUB SPA_VERSION_11 +#define SPA_VERSION_SNAP_PROPS SPA_VERSION_12 /* * ZPL version - rev'd whenever an incompatible on-disk format change