summaryrefslogtreecommitdiff
path: root/cddl
diff options
context:
space:
mode:
Diffstat (limited to 'cddl')
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c19
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c24
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h1
3 files changed, 37 insertions, 7 deletions
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
index b3ae302c0481..de78b5479240 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
@@ -3957,14 +3957,19 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
}
/*
- * We rely on zfs_iter_children() to verify that there are no
- * newer snapshots for the given dataset. Therefore, we can
- * simply pass the name on to the ioctl() call. There is still
- * an unlikely race condition where the user has taken a
- * snapshot since we verified that this was the most recent.
+ * Pass both the filesystem and the wanted snapshot names,
+ * we would get an error back if the snapshot is destroyed or
+ * a new snapshot is created before this request is processed.
*/
- err = lzc_rollback(zhp->zfs_name, NULL, 0);
- if (err != 0) {
+ err = lzc_rollback_to(zhp->zfs_name, snap->zfs_name);
+ if (err == EXDEV) {
+ zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+ "'%s' is not the latest snapshot"), snap->zfs_name);
+ (void) zfs_error_fmt(zhp->zfs_hdl, EZFS_BUSY,
+ dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
+ zhp->zfs_name);
+ return (err);
+ } else if (err != 0) {
(void) zfs_standard_error_fmt(zhp->zfs_hdl, errno,
dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
zhp->zfs_name);
diff --git a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
index 27a414459f95..c38c8c64ee1d 100644
--- a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
+++ b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c
@@ -765,6 +765,9 @@ lzc_receive_with_header(const char *snapname, nvlist_t *props,
* Roll back this filesystem or volume to its most recent snapshot.
* If snapnamebuf is not NULL, it will be filled in with the name
* of the most recent snapshot.
+ * Note that the latest snapshot may change if a new one is concurrently
+ * created or the current one is destroyed. lzc_rollback_to can be used
+ * to roll back to a specific latest snapshot.
*
* Return 0 on success or an errno on failure.
*/
@@ -788,6 +791,27 @@ lzc_rollback(const char *fsname, char *snapnamebuf, int snapnamelen)
}
/*
+ * Roll back this filesystem or volume to the specified snapshot,
+ * if possible.
+ *
+ * Return 0 on success or an errno on failure.
+ */
+int
+lzc_rollback_to(const char *fsname, const char *snapname)
+{
+ nvlist_t *args;
+ nvlist_t *result;
+ int err;
+
+ args = fnvlist_alloc();
+ fnvlist_add_string(args, "target", snapname);
+ err = lzc_ioctl(ZFS_IOC_ROLLBACK, fsname, args, &result);
+ nvlist_free(args);
+ nvlist_free(result);
+ return (err);
+}
+
+/*
* Creates bookmarks.
*
* The bookmarks nvlist maps from name of the bookmark (e.g. "pool/fs#bmark") to
diff --git a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h
index fd18d5fab4f5..ea0e752e3524 100644
--- a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h
+++ b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h
@@ -84,6 +84,7 @@ int lzc_receive_with_header(const char *, nvlist_t *, const char *, boolean_t,
boolean_t lzc_exists(const char *);
int lzc_rollback(const char *, char *, int);
+int lzc_rollback_to(const char *, const char *);
#ifdef __cplusplus
}