svn commit: r260154 - vendor-sys/illumos/dist/common/zfs vendor-sys/illumos/dist/uts/common/fs/zfs vendor-sys/illumos/dist/uts/common/fs/zfs/sys vendor-sys/illumos/dist/uts/common/sys/fs vendor/ill...
Xin LI
delphij at FreeBSD.org
Wed Jan 1 01:15:57 UTC 2014
Author: delphij
Date: Wed Jan 1 01:15:53 2014
New Revision: 260154
URL: http://svnweb.freebsd.org/changeset/base/260154
Log:
4369 implement zfs bookmarks
4368 zfs send filesystems from readonly pools
llumos/illumos-gate at 78f171005391b928aaf1642b3206c534ed644332
Added:
vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_bookmark.c (contents, props changed)
vendor-sys/illumos/dist/uts/common/fs/zfs/sys/dsl_bookmark.h (contents, props changed)
Modified:
vendor-sys/illumos/dist/common/zfs/zfeature_common.c
vendor-sys/illumos/dist/common/zfs/zfeature_common.h
vendor-sys/illumos/dist/common/zfs/zfs_deleg.c
vendor-sys/illumos/dist/common/zfs/zfs_deleg.h
vendor-sys/illumos/dist/common/zfs/zfs_namecheck.c
vendor-sys/illumos/dist/common/zfs/zfs_namecheck.h
vendor-sys/illumos/dist/common/zfs/zfs_prop.c
vendor-sys/illumos/dist/uts/common/fs/zfs/dmu_diff.c
vendor-sys/illumos/dist/uts/common/fs/zfs/dmu_send.c
vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_dataset.c
vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_destroy.c
vendor-sys/illumos/dist/uts/common/fs/zfs/spa_misc.c
vendor-sys/illumos/dist/uts/common/fs/zfs/sys/dsl_dataset.h
vendor-sys/illumos/dist/uts/common/fs/zfs/sys/dsl_deleg.h
vendor-sys/illumos/dist/uts/common/fs/zfs/zfs_ctldir.c
vendor-sys/illumos/dist/uts/common/fs/zfs/zfs_ioctl.c
vendor-sys/illumos/dist/uts/common/sys/fs/zfs.h
Changes in other areas also in this revision:
Modified:
vendor/illumos/dist/cmd/zfs/zfs_iter.c
vendor/illumos/dist/cmd/zfs/zfs_main.c
vendor/illumos/dist/lib/libzfs/common/libzfs.h
vendor/illumos/dist/lib/libzfs/common/libzfs_dataset.c
vendor/illumos/dist/lib/libzfs/common/libzfs_impl.h
vendor/illumos/dist/lib/libzfs/common/libzfs_iter.c
vendor/illumos/dist/lib/libzfs/common/libzfs_sendrecv.c
vendor/illumos/dist/lib/libzfs_core/common/libzfs_core.c
vendor/illumos/dist/lib/libzfs_core/common/libzfs_core.h
vendor/illumos/dist/lib/pyzfs/common/allow.py
vendor/illumos/dist/man/man1m/zfs.1m
vendor/illumos/dist/man/man5/zpool-features.5
Modified: vendor-sys/illumos/dist/common/zfs/zfeature_common.c
==============================================================================
--- vendor-sys/illumos/dist/common/zfs/zfeature_common.c Wed Jan 1 01:05:38 2014 (r260153)
+++ vendor-sys/illumos/dist/common/zfs/zfeature_common.c Wed Jan 1 01:15:53 2014 (r260154)
@@ -197,4 +197,13 @@ zpool_feature_init(void)
"com.delphix:extensible_dataset", "extensible_dataset",
"Enhanced dataset functionality, used by other features.",
B_FALSE, B_FALSE, B_FALSE, NULL);
+
+ static const spa_feature_t bookmarks_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_BOOKMARKS,
+ "com.delphix:bookmarks", "bookmarks",
+ "\"zfs bookmark\" command",
+ B_TRUE, B_FALSE, B_FALSE, bookmarks_deps);
}
Modified: vendor-sys/illumos/dist/common/zfs/zfeature_common.h
==============================================================================
--- vendor-sys/illumos/dist/common/zfs/zfeature_common.h Wed Jan 1 01:05:38 2014 (r260153)
+++ vendor-sys/illumos/dist/common/zfs/zfeature_common.h Wed Jan 1 01:15:53 2014 (r260154)
@@ -48,6 +48,7 @@ typedef enum spa_feature {
SPA_FEATURE_ENABLED_TXG,
SPA_FEATURE_HOLE_BIRTH,
SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_BOOKMARKS,
SPA_FEATURES
} spa_feature_t;
Modified: vendor-sys/illumos/dist/common/zfs/zfs_deleg.c
==============================================================================
--- vendor-sys/illumos/dist/common/zfs/zfs_deleg.c Wed Jan 1 01:05:38 2014 (r260153)
+++ vendor-sys/illumos/dist/common/zfs/zfs_deleg.c Wed Jan 1 01:15:53 2014 (r260154)
@@ -21,8 +21,11 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
*/
+#include <sys/zfs_context.h>
+
#if defined(_KERNEL)
#include <sys/systm.h>
#include <sys/sunddi.h>
@@ -34,43 +37,34 @@
#include <libnvpair.h>
#include <ctype.h>
#endif
-/* XXX includes zfs_context.h, so why bother with the above? */
#include <sys/dsl_deleg.h>
#include "zfs_prop.h"
#include "zfs_deleg.h"
#include "zfs_namecheck.h"
-/*
- * permission table
- *
- * Keep this table in sorted order
- *
- * This table is used for displaying all permissions for
- * zfs allow
- */
-
zfs_deleg_perm_tab_t zfs_deleg_perm_tab[] = {
- {ZFS_DELEG_PERM_ALLOW, ZFS_DELEG_NOTE_ALLOW},
- {ZFS_DELEG_PERM_CLONE, ZFS_DELEG_NOTE_CLONE },
- {ZFS_DELEG_PERM_CREATE, ZFS_DELEG_NOTE_CREATE },
- {ZFS_DELEG_PERM_DESTROY, ZFS_DELEG_NOTE_DESTROY },
- {ZFS_DELEG_PERM_MOUNT, ZFS_DELEG_NOTE_MOUNT },
- {ZFS_DELEG_PERM_PROMOTE, ZFS_DELEG_NOTE_PROMOTE },
- {ZFS_DELEG_PERM_RECEIVE, ZFS_DELEG_NOTE_RECEIVE },
- {ZFS_DELEG_PERM_RENAME, ZFS_DELEG_NOTE_RENAME },
- {ZFS_DELEG_PERM_ROLLBACK, ZFS_DELEG_NOTE_ROLLBACK },
- {ZFS_DELEG_PERM_SNAPSHOT, ZFS_DELEG_NOTE_SNAPSHOT },
- {ZFS_DELEG_PERM_SHARE, ZFS_DELEG_NOTE_SHARE },
- {ZFS_DELEG_PERM_SEND, ZFS_DELEG_NOTE_SEND },
- {ZFS_DELEG_PERM_USERPROP, ZFS_DELEG_NOTE_USERPROP },
- {ZFS_DELEG_PERM_USERQUOTA, ZFS_DELEG_NOTE_USERQUOTA },
- {ZFS_DELEG_PERM_GROUPQUOTA, ZFS_DELEG_NOTE_GROUPQUOTA },
- {ZFS_DELEG_PERM_USERUSED, ZFS_DELEG_NOTE_USERUSED },
- {ZFS_DELEG_PERM_GROUPUSED, ZFS_DELEG_NOTE_GROUPUSED },
- {ZFS_DELEG_PERM_HOLD, ZFS_DELEG_NOTE_HOLD },
- {ZFS_DELEG_PERM_RELEASE, ZFS_DELEG_NOTE_RELEASE },
- {ZFS_DELEG_PERM_DIFF, ZFS_DELEG_NOTE_DIFF},
- {NULL, ZFS_DELEG_NOTE_NONE }
+ {ZFS_DELEG_PERM_ALLOW},
+ {ZFS_DELEG_PERM_BOOKMARK},
+ {ZFS_DELEG_PERM_CLONE},
+ {ZFS_DELEG_PERM_CREATE},
+ {ZFS_DELEG_PERM_DESTROY},
+ {ZFS_DELEG_PERM_DIFF},
+ {ZFS_DELEG_PERM_MOUNT},
+ {ZFS_DELEG_PERM_PROMOTE},
+ {ZFS_DELEG_PERM_RECEIVE},
+ {ZFS_DELEG_PERM_RENAME},
+ {ZFS_DELEG_PERM_ROLLBACK},
+ {ZFS_DELEG_PERM_SNAPSHOT},
+ {ZFS_DELEG_PERM_SHARE},
+ {ZFS_DELEG_PERM_SEND},
+ {ZFS_DELEG_PERM_USERPROP},
+ {ZFS_DELEG_PERM_USERQUOTA},
+ {ZFS_DELEG_PERM_GROUPQUOTA},
+ {ZFS_DELEG_PERM_USERUSED},
+ {ZFS_DELEG_PERM_GROUPUSED},
+ {ZFS_DELEG_PERM_HOLD},
+ {ZFS_DELEG_PERM_RELEASE},
+ {NULL}
};
static int
Modified: vendor-sys/illumos/dist/common/zfs/zfs_deleg.h
==============================================================================
--- vendor-sys/illumos/dist/common/zfs/zfs_deleg.h Wed Jan 1 01:05:38 2014 (r260153)
+++ vendor-sys/illumos/dist/common/zfs/zfs_deleg.h Wed Jan 1 01:15:53 2014 (r260154)
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
*/
#ifndef _ZFS_DELEG_H
@@ -65,6 +66,7 @@ typedef enum {
ZFS_DELEG_NOTE_HOLD,
ZFS_DELEG_NOTE_RELEASE,
ZFS_DELEG_NOTE_DIFF,
+ ZFS_DELEG_NOTE_BOOKMARK,
ZFS_DELEG_NOTE_NONE
} zfs_deleg_note_t;
Modified: vendor-sys/illumos/dist/common/zfs/zfs_namecheck.c
==============================================================================
--- vendor-sys/illumos/dist/common/zfs/zfs_namecheck.c Wed Jan 1 01:05:38 2014 (r260153)
+++ vendor-sys/illumos/dist/common/zfs/zfs_namecheck.c Wed Jan 1 01:15:53 2014 (r260154)
@@ -22,6 +22,9 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
/*
* Common name validation routines for ZFS. These routines are shared by the
@@ -62,7 +65,7 @@ valid_char(char c)
* [-_.: ]
*/
int
-snapshot_namecheck(const char *path, namecheck_err_t *why, char *what)
+zfs_component_namecheck(const char *path, namecheck_err_t *why, char *what)
{
const char *loc;
@@ -113,7 +116,7 @@ permset_namecheck(const char *path, name
return (-1);
}
- return (snapshot_namecheck(&path[1], why, what));
+ return (zfs_component_namecheck(&path[1], why, what));
}
/*
Modified: vendor-sys/illumos/dist/common/zfs/zfs_namecheck.h
==============================================================================
--- vendor-sys/illumos/dist/common/zfs/zfs_namecheck.h Wed Jan 1 01:05:38 2014 (r260153)
+++ vendor-sys/illumos/dist/common/zfs/zfs_namecheck.h Wed Jan 1 01:15:53 2014 (r260154)
@@ -22,6 +22,9 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
#ifndef _ZFS_NAMECHECK_H
#define _ZFS_NAMECHECK_H
@@ -48,7 +51,7 @@ typedef enum {
int pool_namecheck(const char *, namecheck_err_t *, char *);
int dataset_namecheck(const char *, namecheck_err_t *, char *);
int mountpoint_namecheck(const char *, namecheck_err_t *);
-int snapshot_namecheck(const char *, namecheck_err_t *, char *);
+int zfs_component_namecheck(const char *, namecheck_err_t *, char *);
int permset_namecheck(const char *, namecheck_err_t *, char *);
#ifdef __cplusplus
Modified: vendor-sys/illumos/dist/common/zfs/zfs_prop.c
==============================================================================
--- vendor-sys/illumos/dist/common/zfs/zfs_prop.c Wed Jan 1 01:05:38 2014 (r260153)
+++ vendor-sys/illumos/dist/common/zfs/zfs_prop.c Wed Jan 1 01:15:53 2014 (r260154)
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
@@ -312,7 +312,8 @@ zfs_prop_init(void)
PROP_INHERIT, ZFS_TYPE_FILESYSTEM, "on | off | share(1M) options",
"SHARENFS");
zprop_register_string(ZFS_PROP_TYPE, "type", NULL, PROP_READONLY,
- ZFS_TYPE_DATASET, "filesystem | volume | snapshot", "TYPE");
+ ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK,
+ "filesystem | volume | snapshot | bookmark", "TYPE");
zprop_register_string(ZFS_PROP_SHARESMB, "sharesmb", "off",
PROP_INHERIT, ZFS_TYPE_FILESYSTEM,
"on | off | sharemgr(1M) options", "SHARESMB");
@@ -378,18 +379,18 @@ zfs_prop_init(void)
/* hidden properties */
zprop_register_hidden(ZFS_PROP_CREATETXG, "createtxg", PROP_TYPE_NUMBER,
- PROP_READONLY, ZFS_TYPE_DATASET, "CREATETXG");
+ PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "CREATETXG");
zprop_register_hidden(ZFS_PROP_NUMCLONES, "numclones", PROP_TYPE_NUMBER,
PROP_READONLY, ZFS_TYPE_SNAPSHOT, "NUMCLONES");
zprop_register_hidden(ZFS_PROP_NAME, "name", PROP_TYPE_STRING,
- PROP_READONLY, ZFS_TYPE_DATASET, "NAME");
+ PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "NAME");
zprop_register_hidden(ZFS_PROP_ISCSIOPTIONS, "iscsioptions",
PROP_TYPE_STRING, PROP_INHERIT, ZFS_TYPE_VOLUME, "ISCSIOPTIONS");
zprop_register_hidden(ZFS_PROP_STMF_SHAREINFO, "stmf_sbd_lu",
PROP_TYPE_STRING, PROP_INHERIT, ZFS_TYPE_VOLUME,
"STMF_SBD_LU");
zprop_register_hidden(ZFS_PROP_GUID, "guid", PROP_TYPE_NUMBER,
- PROP_READONLY, ZFS_TYPE_DATASET, "GUID");
+ PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "GUID");
zprop_register_hidden(ZFS_PROP_USERACCOUNTING, "useraccounting",
PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_DATASET,
"USERACCOUNTING");
@@ -402,7 +403,7 @@ zfs_prop_init(void)
/* oddball properties */
zprop_register_impl(ZFS_PROP_CREATION, "creation", PROP_TYPE_NUMBER, 0,
- NULL, PROP_READONLY, ZFS_TYPE_DATASET,
+ NULL, PROP_READONLY, ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK,
"<date>", "CREATION", B_FALSE, B_TRUE, NULL);
}
Modified: vendor-sys/illumos/dist/uts/common/fs/zfs/dmu_diff.c
==============================================================================
--- vendor-sys/illumos/dist/uts/common/fs/zfs/dmu_diff.c Wed Jan 1 01:05:38 2014 (r260153)
+++ vendor-sys/illumos/dist/uts/common/fs/zfs/dmu_diff.c Wed Jan 1 01:15:53 2014 (r260154)
@@ -187,7 +187,7 @@ dmu_diff(const char *tosnap_name, const
return (error);
}
- if (!dsl_dataset_is_before(tosnap, fromsnap)) {
+ if (!dsl_dataset_is_before(tosnap, fromsnap, 0)) {
dsl_dataset_rele(fromsnap, FTAG);
dsl_dataset_rele(tosnap, FTAG);
dsl_pool_rele(dp, FTAG);
Modified: vendor-sys/illumos/dist/uts/common/fs/zfs/dmu_send.c
==============================================================================
--- vendor-sys/illumos/dist/uts/common/fs/zfs/dmu_send.c Wed Jan 1 01:05:38 2014 (r260153)
+++ vendor-sys/illumos/dist/uts/common/fs/zfs/dmu_send.c Wed Jan 1 01:15:53 2014 (r260154)
@@ -48,6 +48,7 @@
#include <sys/zfs_onexit.h>
#include <sys/dmu_send.h>
#include <sys/dsl_destroy.h>
+#include <sys/dsl_bookmark.h>
/* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */
int zfs_send_corrupt_data = B_FALSE;
@@ -356,6 +357,12 @@ backup_cb(spa_t *spa, zilog_t *zilog, co
if (zb->zb_object != DMU_META_DNODE_OBJECT &&
DMU_OBJECT_IS_SPECIAL(zb->zb_object)) {
return (0);
+ } else if (zb->zb_level == ZB_ZIL_LEVEL) {
+ /*
+ * If we are sending a non-snapshot (which is allowed on
+ * read-only pools), it may have a ZIL, which must be ignored.
+ */
+ return (0);
} else if (BP_IS_HOLE(bp) &&
zb->zb_object == DMU_META_DNODE_OBJECT) {
uint64_t span = BP_SPAN(dnp, zb->zb_level);
@@ -404,6 +411,7 @@ backup_cb(spa_t *spa, zilog_t *zilog, co
arc_buf_t *abuf;
int blksz = BP_GET_LSIZE(bp);
+ ASSERT0(zb->zb_level);
if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf,
ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL,
&aflags, zb) != 0) {
@@ -431,11 +439,12 @@ backup_cb(spa_t *spa, zilog_t *zilog, co
}
/*
- * Releases dp, ds, and fromds, using the specified tag.
+ * Releases dp using the specified tag.
*/
static int
dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds,
- dsl_dataset_t *fromds, int outfd, vnode_t *vp, offset_t *off)
+ zfs_bookmark_phys_t *fromzb, boolean_t is_clone, int outfd,
+ vnode_t *vp, offset_t *off)
{
objset_t *os;
dmu_replay_record_t *drr;
@@ -443,18 +452,8 @@ dmu_send_impl(void *tag, dsl_pool_t *dp,
int err;
uint64_t fromtxg = 0;
- if (fromds != NULL && !dsl_dataset_is_before(ds, fromds)) {
- dsl_dataset_rele(fromds, tag);
- dsl_dataset_rele(ds, tag);
- dsl_pool_rele(dp, tag);
- return (SET_ERROR(EXDEV));
- }
-
err = dmu_objset_from_ds(ds, &os);
if (err != 0) {
- if (fromds != NULL)
- dsl_dataset_rele(fromds, tag);
- dsl_dataset_rele(ds, tag);
dsl_pool_rele(dp, tag);
return (err);
}
@@ -470,9 +469,6 @@ dmu_send_impl(void *tag, dsl_pool_t *dp,
uint64_t version;
if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &version) != 0) {
kmem_free(drr, sizeof (dmu_replay_record_t));
- if (fromds != NULL)
- dsl_dataset_rele(fromds, tag);
- dsl_dataset_rele(ds, tag);
dsl_pool_rele(dp, tag);
return (SET_ERROR(EINVAL));
}
@@ -487,20 +483,20 @@ dmu_send_impl(void *tag, dsl_pool_t *dp,
drr->drr_u.drr_begin.drr_creation_time =
ds->ds_phys->ds_creation_time;
drr->drr_u.drr_begin.drr_type = dmu_objset_type(os);
- if (fromds != NULL && ds->ds_dir != fromds->ds_dir)
+ if (is_clone)
drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE;
drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid;
if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET)
drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA;
- if (fromds != NULL)
- drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid;
+ if (fromzb != NULL) {
+ drr->drr_u.drr_begin.drr_fromguid = fromzb->zbm_guid;
+ fromtxg = fromzb->zbm_creation_txg;
+ }
dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname);
-
- if (fromds != NULL) {
- fromtxg = fromds->ds_phys->ds_creation_txg;
- dsl_dataset_rele(fromds, tag);
- fromds = NULL;
+ if (!dsl_dataset_is_snapshot(ds)) {
+ (void) strlcat(drr->drr_u.drr_begin.drr_toname, "@--head--",
+ sizeof (drr->drr_u.drr_begin.drr_toname));
}
dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP);
@@ -514,7 +510,7 @@ dmu_send_impl(void *tag, dsl_pool_t *dp,
dsp->dsa_toguid = ds->ds_phys->ds_guid;
ZIO_SET_CHECKSUM(&dsp->dsa_zc, 0, 0, 0, 0);
dsp->dsa_pending_op = PENDING_NONE;
- dsp->dsa_incremental = (fromtxg != 0);
+ dsp->dsa_incremental = (fromzb != NULL);
mutex_enter(&ds->ds_sendstream_lock);
list_insert_head(&ds->ds_sendstreams, dsp);
@@ -560,7 +556,6 @@ out:
kmem_free(dsp, sizeof (dmu_sendarg_t));
dsl_dataset_long_rele(ds, FTAG);
- dsl_dataset_rele(ds, tag);
return (err);
}
@@ -585,15 +580,30 @@ dmu_send_obj(const char *pool, uint64_t
}
if (fromsnap != 0) {
+ zfs_bookmark_phys_t zb;
+ boolean_t is_clone;
+
err = dsl_dataset_hold_obj(dp, fromsnap, FTAG, &fromds);
if (err != 0) {
dsl_dataset_rele(ds, FTAG);
dsl_pool_rele(dp, FTAG);
return (err);
}
+ if (!dsl_dataset_is_before(ds, fromds, 0))
+ err = SET_ERROR(EXDEV);
+ zb.zbm_creation_time = fromds->ds_phys->ds_creation_time;
+ zb.zbm_creation_txg = fromds->ds_phys->ds_creation_txg;
+ zb.zbm_guid = fromds->ds_phys->ds_guid;
+ is_clone = (fromds->ds_dir != ds->ds_dir);
+ dsl_dataset_rele(fromds, FTAG);
+ err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone,
+ outfd, vp, off);
+ } else {
+ err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE,
+ outfd, vp, off);
}
-
- return (dmu_send_impl(FTAG, dp, ds, fromds, outfd, vp, off));
+ dsl_dataset_rele(ds, FTAG);
+ return (err);
}
int
@@ -602,33 +612,79 @@ dmu_send(const char *tosnap, const char
{
dsl_pool_t *dp;
dsl_dataset_t *ds;
- dsl_dataset_t *fromds = NULL;
int err;
+ boolean_t owned = B_FALSE;
- if (strchr(tosnap, '@') == NULL)
- return (SET_ERROR(EINVAL));
- if (fromsnap != NULL && strchr(fromsnap, '@') == NULL)
+ if (fromsnap != NULL && strpbrk(fromsnap, "@#") == NULL)
return (SET_ERROR(EINVAL));
err = dsl_pool_hold(tosnap, FTAG, &dp);
if (err != 0)
return (err);
- err = dsl_dataset_hold(dp, tosnap, FTAG, &ds);
+ if (strchr(tosnap, '@') == NULL && spa_writeable(dp->dp_spa)) {
+ /*
+ * We are sending a filesystem or volume. Ensure
+ * that it doesn't change by owning the dataset.
+ */
+ err = dsl_dataset_own(dp, tosnap, FTAG, &ds);
+ owned = B_TRUE;
+ } else {
+ err = dsl_dataset_hold(dp, tosnap, FTAG, &ds);
+ }
if (err != 0) {
dsl_pool_rele(dp, FTAG);
return (err);
}
if (fromsnap != NULL) {
- err = dsl_dataset_hold(dp, fromsnap, FTAG, &fromds);
+ zfs_bookmark_phys_t zb;
+ boolean_t is_clone = B_FALSE;
+ int fsnamelen = strchr(tosnap, '@') - tosnap;
+
+ /*
+ * If the fromsnap is in a different filesystem, then
+ * mark the send stream as a clone.
+ */
+ if (strncmp(tosnap, fromsnap, fsnamelen) != 0 ||
+ (fromsnap[fsnamelen] != '@' &&
+ fromsnap[fsnamelen] != '#')) {
+ is_clone = B_TRUE;
+ }
+
+ if (strchr(fromsnap, '@')) {
+ dsl_dataset_t *fromds;
+ err = dsl_dataset_hold(dp, fromsnap, FTAG, &fromds);
+ if (err == 0) {
+ if (!dsl_dataset_is_before(ds, fromds, 0))
+ err = SET_ERROR(EXDEV);
+ zb.zbm_creation_time =
+ fromds->ds_phys->ds_creation_time;
+ zb.zbm_creation_txg =
+ fromds->ds_phys->ds_creation_txg;
+ zb.zbm_guid = fromds->ds_phys->ds_guid;
+ is_clone = (ds->ds_dir != fromds->ds_dir);
+ dsl_dataset_rele(fromds, FTAG);
+ }
+ } else {
+ err = dsl_bookmark_lookup(dp, fromsnap, ds, &zb);
+ }
if (err != 0) {
dsl_dataset_rele(ds, FTAG);
dsl_pool_rele(dp, FTAG);
return (err);
}
+ err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone,
+ outfd, vp, off);
+ } else {
+ err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE,
+ outfd, vp, off);
}
- return (dmu_send_impl(FTAG, dp, ds, fromds, outfd, vp, off));
+ if (owned)
+ dsl_dataset_disown(ds, FTAG);
+ else
+ dsl_dataset_rele(ds, FTAG);
+ return (err);
}
int
@@ -648,7 +704,7 @@ dmu_send_estimate(dsl_dataset_t *ds, dsl
* fromsnap must be an earlier snapshot from the same fs as tosnap,
* or the origin's fs.
*/
- if (fromds != NULL && !dsl_dataset_is_before(ds, fromds))
+ if (fromds != NULL && !dsl_dataset_is_before(ds, fromds, 0))
return (SET_ERROR(EXDEV));
/* Get uncompressed size estimate of changed data. */
Added: vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_bookmark.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_bookmark.c Wed Jan 1 01:15:53 2014 (r260154)
@@ -0,0 +1,454 @@
+/*
+ * CDDL HEADER START
+ *
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_synctask.h>
+#include <sys/dmu_impl.h>
+#include <sys/dmu_tx.h>
+#include <sys/arc.h>
+#include <sys/zap.h>
+#include <sys/zfeature.h>
+#include <sys/spa.h>
+#include <sys/dsl_bookmark.h>
+#include <zfs_namecheck.h>
+
+static int
+dsl_bookmark_hold_ds(dsl_pool_t *dp, const char *fullname,
+ dsl_dataset_t **dsp, void *tag, char **shortnamep)
+{
+ char buf[MAXNAMELEN];
+ char *hashp;
+
+ if (strlen(fullname) >= MAXNAMELEN)
+ return (SET_ERROR(ENAMETOOLONG));
+ hashp = strchr(fullname, '#');
+ if (hashp == NULL)
+ return (SET_ERROR(EINVAL));
+
+ *shortnamep = hashp + 1;
+ if (zfs_component_namecheck(*shortnamep, NULL, NULL))
+ return (SET_ERROR(EINVAL));
+ (void) strlcpy(buf, fullname, hashp - fullname + 1);
+ return (dsl_dataset_hold(dp, buf, tag, dsp));
+}
+
+/*
+ * Returns ESRCH if bookmark is not found.
+ */
+static int
+dsl_dataset_bmark_lookup(dsl_dataset_t *ds, const char *shortname,
+ zfs_bookmark_phys_t *bmark_phys)
+{
+ objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+ uint64_t bmark_zapobj = ds->ds_bookmarks;
+ matchtype_t mt;
+ int err;
+
+ if (bmark_zapobj == 0)
+ return (SET_ERROR(ESRCH));
+
+ if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET)
+ mt = MT_FIRST;
+ else
+ mt = MT_EXACT;
+
+ err = zap_lookup_norm(mos, bmark_zapobj, shortname, sizeof (uint64_t),
+ sizeof (*bmark_phys) / sizeof (uint64_t), bmark_phys, mt,
+ NULL, 0, NULL);
+
+ return (err == ENOENT ? ESRCH : err);
+}
+
+/*
+ * If later_ds is non-NULL, this will return EXDEV if the the specified bookmark
+ * does not represents an earlier point in later_ds's timeline.
+ *
+ * Returns ENOENT if the dataset containing the bookmark does not exist.
+ * Returns ESRCH if the dataset exists but the bookmark was not found in it.
+ */
+int
+dsl_bookmark_lookup(dsl_pool_t *dp, const char *fullname,
+ dsl_dataset_t *later_ds, zfs_bookmark_phys_t *bmp)
+{
+ char *shortname;
+ dsl_dataset_t *ds;
+ int error;
+
+ error = dsl_bookmark_hold_ds(dp, fullname, &ds, FTAG, &shortname);
+ if (error != 0)
+ return (error);
+
+ error = dsl_dataset_bmark_lookup(ds, shortname, bmp);
+ if (error == 0 && later_ds != NULL) {
+ if (!dsl_dataset_is_before(later_ds, ds, bmp->zbm_creation_txg))
+ error = SET_ERROR(EXDEV);
+ }
+ dsl_dataset_rele(ds, FTAG);
+ return (error);
+}
+
+typedef struct dsl_bookmark_create_arg {
+ nvlist_t *dbca_bmarks;
+ nvlist_t *dbca_errors;
+} dsl_bookmark_create_arg_t;
+
+static int
+dsl_bookmark_create_check_impl(dsl_dataset_t *snapds, const char *bookmark_name,
+ dmu_tx_t *tx)
+{
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+ dsl_dataset_t *bmark_fs;
+ char *shortname;
+ int error;
+ zfs_bookmark_phys_t bmark_phys;
+
+ if (!dsl_dataset_is_snapshot(snapds))
+ return (SET_ERROR(EINVAL));
+
+ error = dsl_bookmark_hold_ds(dp, bookmark_name,
+ &bmark_fs, FTAG, &shortname);
+ if (error != 0)
+ return (error);
+
+ if (!dsl_dataset_is_before(bmark_fs, snapds, 0)) {
+ dsl_dataset_rele(bmark_fs, FTAG);
+ return (SET_ERROR(EINVAL));
+ }
+
+ error = dsl_dataset_bmark_lookup(bmark_fs, shortname,
+ &bmark_phys);
+ dsl_dataset_rele(bmark_fs, FTAG);
+ if (error == 0)
+ return (SET_ERROR(EEXIST));
+ if (error == ESRCH)
+ return (0);
+ return (error);
+}
+
+static int
+dsl_bookmark_create_check(void *arg, dmu_tx_t *tx)
+{
+ dsl_bookmark_create_arg_t *dbca = arg;
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+ int rv = 0;
+
+ if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_BOOKMARKS))
+ return (SET_ERROR(ENOTSUP));
+
+ for (nvpair_t *pair = nvlist_next_nvpair(dbca->dbca_bmarks, NULL);
+ pair != NULL; pair = nvlist_next_nvpair(dbca->dbca_bmarks, pair)) {
+ dsl_dataset_t *snapds;
+ int error;
+
+ /* note: validity of nvlist checked by ioctl layer */
+ error = dsl_dataset_hold(dp, fnvpair_value_string(pair),
+ FTAG, &snapds);
+ if (error == 0) {
+ error = dsl_bookmark_create_check_impl(snapds,
+ nvpair_name(pair), tx);
+ dsl_dataset_rele(snapds, FTAG);
+ }
+ if (error != 0) {
+ fnvlist_add_int32(dbca->dbca_errors,
+ nvpair_name(pair), error);
+ rv = error;
+ }
+ }
+
+ return (rv);
+}
+
+static void
+dsl_bookmark_create_sync(void *arg, dmu_tx_t *tx)
+{
+ dsl_bookmark_create_arg_t *dbca = arg;
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+ objset_t *mos = dp->dp_meta_objset;
+
+ ASSERT(spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_BOOKMARKS));
+
+ for (nvpair_t *pair = nvlist_next_nvpair(dbca->dbca_bmarks, NULL);
+ pair != NULL; pair = nvlist_next_nvpair(dbca->dbca_bmarks, pair)) {
+ dsl_dataset_t *snapds, *bmark_fs;
+ zfs_bookmark_phys_t bmark_phys;
+ char *shortname;
+
+ VERIFY0(dsl_dataset_hold(dp, fnvpair_value_string(pair),
+ FTAG, &snapds));
+ VERIFY0(dsl_bookmark_hold_ds(dp, nvpair_name(pair),
+ &bmark_fs, FTAG, &shortname));
+ if (bmark_fs->ds_bookmarks == 0) {
+ bmark_fs->ds_bookmarks =
+ zap_create_norm(mos, U8_TEXTPREP_TOUPPER,
+ DMU_OTN_ZAP_METADATA, DMU_OT_NONE, 0, tx);
+ spa_feature_incr(dp->dp_spa, SPA_FEATURE_BOOKMARKS, tx);
+
+ dsl_dataset_zapify(bmark_fs, tx);
+ VERIFY0(zap_add(mos, bmark_fs->ds_object,
+ DS_FIELD_BOOKMARK_NAMES,
+ sizeof (bmark_fs->ds_bookmarks), 1,
+ &bmark_fs->ds_bookmarks, tx));
+ }
+
+ bmark_phys.zbm_guid = snapds->ds_phys->ds_guid;
+ bmark_phys.zbm_creation_txg = snapds->ds_phys->ds_creation_txg;
+ bmark_phys.zbm_creation_time =
+ snapds->ds_phys->ds_creation_time;
+
+ VERIFY0(zap_add(mos, bmark_fs->ds_bookmarks,
+ shortname, sizeof (uint64_t),
+ sizeof (zfs_bookmark_phys_t) / sizeof (uint64_t),
+ &bmark_phys, tx));
+
+ spa_history_log_internal_ds(bmark_fs, "bookmark", tx,
+ "name=%s creation_txg=%llu target_snap=%llu",
+ shortname,
+ (longlong_t)bmark_phys.zbm_creation_txg,
+ (longlong_t)snapds->ds_object);
+
+ dsl_dataset_rele(bmark_fs, FTAG);
+ dsl_dataset_rele(snapds, FTAG);
+ }
+}
+
+/*
+ * The bookmarks must all be in the same pool.
+ */
+int
+dsl_bookmark_create(nvlist_t *bmarks, nvlist_t *errors)
+{
+ nvpair_t *pair;
+ dsl_bookmark_create_arg_t dbca;
+
+ pair = nvlist_next_nvpair(bmarks, NULL);
+ if (pair == NULL)
+ return (0);
+
+ dbca.dbca_bmarks = bmarks;
+ dbca.dbca_errors = errors;
+
+ return (dsl_sync_task(nvpair_name(pair), dsl_bookmark_create_check,
+ dsl_bookmark_create_sync, &dbca, fnvlist_num_pairs(bmarks)));
+}
+
+int
+dsl_get_bookmarks_impl(dsl_dataset_t *ds, nvlist_t *props, nvlist_t *outnvl)
+{
+ int err = 0;
+ zap_cursor_t zc;
+ zap_attribute_t attr;
+ dsl_pool_t *dp = ds->ds_dir->dd_pool;
+
+ uint64_t bmark_zapobj = ds->ds_bookmarks;
+ if (bmark_zapobj == 0)
+ return (0);
+
+ for (zap_cursor_init(&zc, dp->dp_meta_objset, bmark_zapobj);
+ zap_cursor_retrieve(&zc, &attr) == 0;
+ zap_cursor_advance(&zc)) {
+ char *bmark_name = attr.za_name;
+ zfs_bookmark_phys_t bmark_phys;
+
+ err = dsl_dataset_bmark_lookup(ds, bmark_name, &bmark_phys);
+ ASSERT3U(err, !=, ENOENT);
+ if (err != 0)
+ break;
+
+ nvlist_t *out_props = fnvlist_alloc();
+ if (nvlist_exists(props,
+ zfs_prop_to_name(ZFS_PROP_GUID))) {
+ dsl_prop_nvlist_add_uint64(out_props,
+ ZFS_PROP_GUID, bmark_phys.zbm_guid);
+ }
+ if (nvlist_exists(props,
+ zfs_prop_to_name(ZFS_PROP_CREATETXG))) {
+ dsl_prop_nvlist_add_uint64(out_props,
+ ZFS_PROP_CREATETXG, bmark_phys.zbm_creation_txg);
+ }
+ if (nvlist_exists(props,
+ zfs_prop_to_name(ZFS_PROP_CREATION))) {
+ dsl_prop_nvlist_add_uint64(out_props,
+ ZFS_PROP_CREATION, bmark_phys.zbm_creation_time);
+ }
+
+ fnvlist_add_nvlist(outnvl, bmark_name, out_props);
+ fnvlist_free(out_props);
+ }
+ zap_cursor_fini(&zc);
+ return (err);
+}
+
+/*
+ * Retrieve the bookmarks that exist in the specified dataset, and the
+ * requested properties of each bookmark.
+ *
+ * The "props" nvlist specifies which properties are requested.
+ * See lzc_get_bookmarks() for the list of valid properties.
+ */
+int
+dsl_get_bookmarks(const char *dsname, nvlist_t *props, nvlist_t *outnvl)
+{
+ dsl_pool_t *dp;
+ dsl_dataset_t *ds;
+ int err;
+
+ err = dsl_pool_hold(dsname, FTAG, &dp);
+ if (err != 0)
+ return (err);
+ err = dsl_dataset_hold(dp, dsname, FTAG, &ds);
+ if (err != 0) {
+ dsl_pool_rele(dp, FTAG);
+ return (err);
+ }
+
+ err = dsl_get_bookmarks_impl(ds, props, outnvl);
+
+ dsl_dataset_rele(ds, FTAG);
+ dsl_pool_rele(dp, FTAG);
+ return (err);
+}
+
+typedef struct dsl_bookmark_destroy_arg {
+ nvlist_t *dbda_bmarks;
+ nvlist_t *dbda_success;
+ nvlist_t *dbda_errors;
+} dsl_bookmark_destroy_arg_t;
+
+static int
+dsl_dataset_bookmark_remove(dsl_dataset_t *ds, const char *name, dmu_tx_t *tx)
+{
+ objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
+ uint64_t bmark_zapobj = ds->ds_bookmarks;
+ matchtype_t mt;
+
+ if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET)
+ mt = MT_FIRST;
+ else
+ mt = MT_EXACT;
+
+ return (zap_remove_norm(mos, bmark_zapobj, name, mt, tx));
+}
+
+static int
+dsl_bookmark_destroy_check(void *arg, dmu_tx_t *tx)
+{
+ dsl_bookmark_destroy_arg_t *dbda = arg;
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+ int rv = 0;
+
+ if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_BOOKMARKS))
+ return (0);
+
+ for (nvpair_t *pair = nvlist_next_nvpair(dbda->dbda_bmarks, NULL);
+ pair != NULL; pair = nvlist_next_nvpair(dbda->dbda_bmarks, pair)) {
+ const char *fullname = nvpair_name(pair);
+ dsl_dataset_t *ds;
+ zfs_bookmark_phys_t bm;
+ int error;
+ char *shortname;
+
+ error = dsl_bookmark_hold_ds(dp, fullname, &ds,
+ FTAG, &shortname);
+ if (error == ENOENT) {
+ /* ignore it; the bookmark is "already destroyed" */
+ continue;
+ }
+ if (error == 0) {
+ error = dsl_dataset_bmark_lookup(ds, shortname, &bm);
+ dsl_dataset_rele(ds, FTAG);
+ if (error == ESRCH) {
+ /*
+ * ignore it; the bookmark is
+ * "already destroyed"
+ */
+ continue;
+ }
+ }
+ if (error == 0) {
+ fnvlist_add_boolean(dbda->dbda_success, fullname);
+ } else {
+ fnvlist_add_int32(dbda->dbda_errors, fullname, error);
+ rv = error;
+ }
+ }
+ return (rv);
+}
+
+static void
+dsl_bookmark_destroy_sync(void *arg, dmu_tx_t *tx)
+{
+ dsl_bookmark_destroy_arg_t *dbda = arg;
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+ objset_t *mos = dp->dp_meta_objset;
+
+ for (nvpair_t *pair = nvlist_next_nvpair(dbda->dbda_success, NULL);
+ pair != NULL; pair = nvlist_next_nvpair(dbda->dbda_success, pair)) {
+ dsl_dataset_t *ds;
+ char *shortname;
+ uint64_t zap_cnt;
+
+ VERIFY0(dsl_bookmark_hold_ds(dp, nvpair_name(pair),
+ &ds, FTAG, &shortname));
+ VERIFY0(dsl_dataset_bookmark_remove(ds, shortname, tx));
+
+ /*
+ * If all of this dataset's bookmarks have been destroyed,
+ * free the zap object and decrement the feature's use count.
+ */
+ VERIFY0(zap_count(mos, ds->ds_bookmarks,
+ &zap_cnt));
+ if (zap_cnt == 0) {
+ dmu_buf_will_dirty(ds->ds_dbuf, tx);
+ VERIFY0(zap_destroy(mos, ds->ds_bookmarks, tx));
+ ds->ds_bookmarks = 0;
+ spa_feature_decr(dp->dp_spa, SPA_FEATURE_BOOKMARKS, tx);
+ VERIFY0(zap_remove(mos, ds->ds_object,
+ DS_FIELD_BOOKMARK_NAMES, tx));
+ }
+
+ spa_history_log_internal_ds(ds, "remove bookmark", tx,
+ "name=%s", shortname);
+
+ dsl_dataset_rele(ds, FTAG);
+ }
+}
+
+/*
+ * The bookmarks must all be in the same pool.
+ */
+int
+dsl_bookmark_destroy(nvlist_t *bmarks, nvlist_t *errors)
+{
+ int rv;
+ dsl_bookmark_destroy_arg_t dbda;
+ nvpair_t *pair = nvlist_next_nvpair(bmarks, NULL);
+ if (pair == NULL)
+ return (0);
+
+ dbda.dbda_bmarks = bmarks;
+ dbda.dbda_errors = errors;
+ dbda.dbda_success = fnvlist_alloc();
+
+ rv = dsl_sync_task(nvpair_name(pair), dsl_bookmark_destroy_check,
+ dsl_bookmark_destroy_sync, &dbda, fnvlist_num_pairs(bmarks));
+ fnvlist_free(dbda.dbda_success);
+ return (rv);
+}
Modified: vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_dataset.c
==============================================================================
--- vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_dataset.c Wed Jan 1 01:05:38 2014 (r260153)
+++ vendor-sys/illumos/dist/uts/common/fs/zfs/dsl_dataset.c Wed Jan 1 01:15:53 2014 (r260154)
@@ -47,6 +47,7 @@
#include <sys/dsl_deadlist.h>
#include <sys/dsl_destroy.h>
#include <sys/dsl_userhold.h>
+#include <sys/dsl_bookmark.h>
#define SWITCH64(x, y) \
{ \
@@ -400,6 +401,14 @@ dsl_dataset_hold_obj(dsl_pool_t *dp, uin
ds->ds_phys->ds_prev_snap_obj,
ds, &ds->ds_prev);
}
+ if (doi.doi_type == DMU_OTN_ZAP_METADATA) {
+ int zaperr = zap_lookup(mos, ds->ds_object,
+ DS_FIELD_BOOKMARK_NAMES,
+ sizeof (ds->ds_bookmarks), 1,
+ &ds->ds_bookmarks);
+ if (zaperr != ENOENT)
+ VERIFY0(zaperr);
+ }
} else {
if (zfs_flags & ZFS_DEBUG_SNAPNAMES)
err = dsl_dataset_get_snapname(ds);
@@ -1721,6 +1730,28 @@ dsl_dataset_rollback_check(void *arg, dm
return (SET_ERROR(EINVAL));
}
+ /* must not have any bookmarks after the most recent snapshot */
+ nvlist_t *proprequest = fnvlist_alloc();
+ fnvlist_add_boolean(proprequest, zfs_prop_to_name(ZFS_PROP_CREATETXG));
+ nvlist_t *bookmarks = fnvlist_alloc();
+ error = dsl_get_bookmarks_impl(ds, proprequest, bookmarks);
+ fnvlist_free(proprequest);
+ if (error != 0)
+ return (error);
+ for (nvpair_t *pair = nvlist_next_nvpair(bookmarks, NULL);
+ pair != NULL; pair = nvlist_next_nvpair(bookmarks, pair)) {
+ nvlist_t *valuenv =
+ fnvlist_lookup_nvlist(fnvpair_value_nvlist(pair),
+ zfs_prop_to_name(ZFS_PROP_CREATETXG));
+ uint64_t createtxg = fnvlist_lookup_uint64(valuenv, "value");
+ if (createtxg > ds->ds_phys->ds_prev_snap_txg) {
+ fnvlist_free(bookmarks);
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EEXIST));
+ }
+ }
+ fnvlist_free(bookmarks);
+
error = dsl_dataset_handoff_check(ds, ddra->ddra_owner, tx);
if (error != 0) {
dsl_dataset_rele(ds, FTAG);
@@ -2942,18 +2973,25 @@ dsl_dataset_space_wouldfree(dsl_dataset_
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-all
mailing list