From 8ddfd821ab8220826eb02d69a9f6150958877bbf Mon Sep 17 00:00:00 2001 From: delphij Date: Wed, 19 Mar 2014 23:21:31 +0000 Subject: [PATCH] MFC r254587: MFV r254421: Illumos ZFS issues: 3996 want a libzfs_core API to rollback to latest snapshot git-svn-id: svn://svn.freebsd.org/base/stable/9@263386 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- .../lib/libzfs/common/libzfs_dataset.c | 12 ++------- .../lib/libzfs_core/common/libzfs_core.c | 26 ++++++++++++++++++- .../lib/libzfs_core/common/libzfs_core.h | 3 ++- .../uts/common/fs/zfs/dsl_dataset.c | 15 ++++++++--- .../uts/common/fs/zfs/sys/dsl_dataset.h | 2 +- .../opensolaris/uts/common/fs/zfs/zfs_ioctl.c | 25 +++++++++++------- 6 files changed, 57 insertions(+), 26 deletions(-) diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c index 751844a0b..2f31c1a09 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c @@ -3572,7 +3572,6 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) { rollback_data_t cb = { 0 }; int err; - zfs_cmd_t zc = { 0 }; boolean_t restore_resv = 0; uint64_t old_volsize, new_volsize; zfs_prop_t resv_prop; @@ -3604,22 +3603,15 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force) (old_volsize == zfs_prop_get_int(zhp, resv_prop)); } - (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); - - if (ZFS_IS_VOLUME(zhp)) - zc.zc_objset_type = DMU_OST_ZVOL; - else - zc.zc_objset_type = DMU_OST_ZFS; - /* * 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. - * */ - if ((err = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_ROLLBACK, &zc)) != 0) { + err = lzc_rollback(zhp->zfs_name, NULL, 0); + 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 c5c3b0e23..6f4b46cf2 100644 --- a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c +++ b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c @@ -20,7 +20,7 @@ */ /* - * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved. */ @@ -628,3 +628,27 @@ out: free((void*)(uintptr_t)zc.zc_nvlist_dst); return (error); } + +/* + * 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. + * + * Return 0 on success or an errno on failure. + */ +int +lzc_rollback(const char *fsname, char *snapnamebuf, int snapnamelen) +{ + nvlist_t *args; + nvlist_t *result; + int err; + + args = fnvlist_alloc(); + err = lzc_ioctl(ZFS_IOC_ROLLBACK, fsname, args, &result); + nvlist_free(args); + if (err == 0 && snapnamebuf != NULL) { + const char *snapname = fnvlist_lookup_string(result, "target"); + (void) strlcpy(snapnamebuf, snapname, snapnamelen); + } + return (err); +} 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 b10098b37..c55caf44f 100644 --- a/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h +++ b/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.h @@ -20,7 +20,7 @@ */ /* - * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. * Copyright (c) 2013 by Martin Matuska . All rights reserved. */ @@ -59,6 +59,7 @@ int lzc_send_space(const char *snapname, const char *fromsnap, boolean_t lzc_exists(const char *dataset); +int lzc_rollback(const char *fsname, char *snapnamebuf, int snapnamelen); #ifdef __cplusplus } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c index 37a6a9d02..4af2da5de 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c @@ -1774,6 +1774,7 @@ dsl_dataset_handoff_check(dsl_dataset_t *ds, void *owner, dmu_tx_t *tx) typedef struct dsl_dataset_rollback_arg { const char *ddra_fsname; void *ddra_owner; + nvlist_t *ddra_result; } dsl_dataset_rollback_arg_t; static int @@ -1845,9 +1846,13 @@ dsl_dataset_rollback_sync(void *arg, dmu_tx_t *tx) dsl_pool_t *dp = dmu_tx_pool(tx); dsl_dataset_t *ds, *clone; uint64_t cloneobj; + char namebuf[ZFS_MAXNAMELEN]; VERIFY0(dsl_dataset_hold(dp, ddra->ddra_fsname, FTAG, &ds)); + dsl_dataset_name(ds->ds_prev, namebuf); + fnvlist_add_string(ddra->ddra_result, "target", namebuf); + cloneobj = dsl_dataset_create_sync(ds->ds_dir, "%rollback", ds->ds_prev, DS_CREATE_FLAG_NODIRTY, kcred, tx); @@ -1863,8 +1868,11 @@ dsl_dataset_rollback_sync(void *arg, dmu_tx_t *tx) } /* - * If owner != NULL: + * Rolls back the given filesystem or volume to the most recent snapshot. + * The name of the most recent snapshot will be returned under key "target" + * in the result nvlist. * + * If owner != NULL: * - The existing dataset MUST be owned by the specified owner at entry * - Upon return, dataset will still be held by the same owner, whether we * succeed or not. @@ -1873,15 +1881,16 @@ dsl_dataset_rollback_sync(void *arg, dmu_tx_t *tx) * notes above zfs_suspend_fs() for further details. */ int -dsl_dataset_rollback(const char *fsname, void *owner) +dsl_dataset_rollback(const char *fsname, void *owner, nvlist_t *result) { dsl_dataset_rollback_arg_t ddra; ddra.ddra_fsname = fsname; ddra.ddra_owner = owner; + ddra.ddra_result = result; return (dsl_sync_task(fsname, dsl_dataset_rollback_check, - dsl_dataset_rollback_sync, (void *)&ddra, 1)); + dsl_dataset_rollback_sync, &ddra, 1)); } struct promotenode { diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h index fa7cad7f7..5605e9298 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h @@ -265,7 +265,7 @@ int dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name, int dsl_dataset_snap_remove(dsl_dataset_t *ds, const char *name, dmu_tx_t *tx); void dsl_dataset_set_refreservation_sync_impl(dsl_dataset_t *ds, zprop_source_t source, uint64_t value, dmu_tx_t *tx); -int dsl_dataset_rollback(const char *fsname, void *owner); +int dsl_dataset_rollback(const char *fsname, void *owner, nvlist_t *result); #ifdef ZFS_DEBUG #define dprintf_ds(ds, fmt, ...) do { \ diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c index e12edca1f..4bb9ddc95 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c @@ -3552,29 +3552,32 @@ zfs_ioc_destroy(zfs_cmd_t *zc) } /* - * inputs: - * zc_name name of dataset to rollback (to most recent snapshot) + * fsname is name of dataset to rollback (to most recent snapshot) * - * outputs: none + * innvl is not used. + * + * outnvl: "target" -> name of most recent snapshot + * } */ +/* ARGSUSED */ static int -zfs_ioc_rollback(zfs_cmd_t *zc) +zfs_ioc_rollback(const char *fsname, nvlist_t *args, nvlist_t *outnvl) { zfsvfs_t *zfsvfs; int error; - if (getzfsvfs(zc->zc_name, &zfsvfs) == 0) { + if (getzfsvfs(fsname, &zfsvfs) == 0) { error = zfs_suspend_fs(zfsvfs); if (error == 0) { int resume_err; - error = dsl_dataset_rollback(zc->zc_name, zfsvfs); - resume_err = zfs_resume_fs(zfsvfs, zc->zc_name); + error = dsl_dataset_rollback(fsname, zfsvfs, outnvl); + resume_err = zfs_resume_fs(zfsvfs, fsname); error = error ? error : resume_err; } VFS_RELE(zfsvfs->z_vfs); } else { - error = dsl_dataset_rollback(zc->zc_name, NULL); + error = dsl_dataset_rollback(fsname, NULL, outnvl); } return (error); } @@ -5448,6 +5451,10 @@ zfs_ioctl_init(void) zfs_ioc_get_holds, zfs_secpolicy_read, DATASET_NAME, POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE); + zfs_ioctl_register("rollback", ZFS_IOC_ROLLBACK, + zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME, + POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_TRUE); + /* IOCTLS that use the legacy function signature */ zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze, @@ -5559,8 +5566,6 @@ zfs_ioctl_init(void) zfs_secpolicy_none); zfs_ioctl_register_dataset_modify(ZFS_IOC_DESTROY, zfs_ioc_destroy, zfs_secpolicy_destroy); - zfs_ioctl_register_dataset_modify(ZFS_IOC_ROLLBACK, zfs_ioc_rollback, - zfs_secpolicy_rollback); zfs_ioctl_register_dataset_modify(ZFS_IOC_RENAME, zfs_ioc_rename, zfs_secpolicy_rename); zfs_ioctl_register_dataset_modify(ZFS_IOC_RECV, zfs_ioc_recv, -- 2.45.0