diff --git a/include/sys/dsl_dataset.h b/include/sys/dsl_dataset.h index 4bf0cb31f9..ee822a2014 100644 --- a/include/sys/dsl_dataset.h +++ b/include/sys/dsl_dataset.h @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, 2016 by Delphix. All rights reserved. + * Copyright (c) 2011, 2017 by Delphix. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. */ @@ -245,6 +245,13 @@ typedef struct dsl_dataset_promote_arg { cred_t *cr; } dsl_dataset_promote_arg_t; +typedef struct dsl_dataset_rollback_arg { + const char *ddra_fsname; + const char *ddra_tosnap; + void *ddra_owner; + nvlist_t *ddra_result; +} dsl_dataset_rollback_arg_t; + /* * The max length of a temporary tag prefix is the number of hex digits * required to express UINT64_MAX plus one for the hyphen. @@ -394,6 +401,9 @@ void dsl_dataset_set_refreservation_sync_impl(dsl_dataset_t *ds, void dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx); boolean_t dsl_dataset_is_zapified(dsl_dataset_t *ds); boolean_t dsl_dataset_has_resume_receive_state(dsl_dataset_t *ds); + +int dsl_dataset_rollback_check(void *arg, dmu_tx_t *tx); +void dsl_dataset_rollback_sync(void *arg, dmu_tx_t *tx); int dsl_dataset_rollback(const char *fsname, const char *tosnap, void *owner, nvlist_t *result); diff --git a/man/man8/zfs-program.8 b/man/man8/zfs-program.8 index 2e4e9587d5..4c7d86ef12 100644 --- a/man/man8/zfs-program.8 +++ b/man/man8/zfs-program.8 @@ -8,7 +8,7 @@ .\" http://www.illumos.org/license/CDDL. .\" .\" -.\" Copyright (c) 2016 by Delphix. All Rights Reserved. +.\" Copyright (c) 2016, 2017 by Delphix. All Rights Reserved. .\" .Dd January 21, 2016 .Dt ZFS-PROGRAM 8 @@ -361,6 +361,17 @@ dataset (string) .Bd -ragged -compact -offset "xxxx" Clone to be promoted. .Ed +.It Em zfs.sync.rollback(filesystem) +Rollback to the previous snapshot for a dataset. +Returns 0 on successful rollback, or a nonzero error code otherwise. +Rollbacks can be performed on filesystems or zvols, but not on snapshots +or mounted datasets. +EBUSY is returned in the case where the filesystem is mounted. +.Pp +filesystem (string) +.Bd -ragged -compact -offset "xxxx" +Filesystem to rollback. +.Ed .El .It Sy zfs.check submodule For each function in the zfs.sync submodule, there is a corresponding zfs.check @@ -380,6 +391,7 @@ The available zfs.check functions are: .Bl -tag -width "xx" .It Em zfs.check.destroy(dataset, [defer=true|false]) .It Em zfs.check.promote(dataset) +.It Em zfs.check.rollback(filesystem) .El .It Sy zfs.list submodule The zfs.list submodule provides functions for iterating over datasets and diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index af3dc230a2..a35ba1f7ed 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2011, 2016 by Delphix. All rights reserved. + * Copyright (c) 2011, 2017 by Delphix. All rights reserved. * Copyright (c) 2014, Joyent, Inc. All rights reserved. * Copyright (c) 2014 RackTop Systems. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. @@ -2526,14 +2526,7 @@ dsl_dataset_handoff_check(dsl_dataset_t *ds, void *owner, dmu_tx_t *tx) return (0); } -typedef struct dsl_dataset_rollback_arg { - const char *ddra_fsname; - const char *ddra_tosnap; - void *ddra_owner; - nvlist_t *ddra_result; -} dsl_dataset_rollback_arg_t; - -static int +int dsl_dataset_rollback_check(void *arg, dmu_tx_t *tx) { dsl_dataset_rollback_arg_t *ddra = arg; @@ -2641,7 +2634,7 @@ dsl_dataset_rollback_check(void *arg, dmu_tx_t *tx) return (0); } -static void +void dsl_dataset_rollback_sync(void *arg, dmu_tx_t *tx) { dsl_dataset_rollback_arg_t *ddra = arg; diff --git a/module/zfs/zcp_synctask.c b/module/zfs/zcp_synctask.c index 923d5ca673..93797e9f35 100644 --- a/module/zfs/zcp_synctask.c +++ b/module/zfs/zcp_synctask.c @@ -14,7 +14,7 @@ */ /* - * Copyright (c) 2016 by Delphix. All rights reserved. + * Copyright (c) 2016, 2017 by Delphix. All rights reserved. */ #include @@ -177,6 +177,37 @@ zcp_synctask_promote(lua_State *state, boolean_t sync, nvlist_t *err_details) return (err); } +static int zcp_synctask_rollback(lua_State *, boolean_t, nvlist_t *err_details); +static zcp_synctask_info_t zcp_synctask_rollback_info = { + .name = "rollback", + .func = zcp_synctask_rollback, + .space_check = ZFS_SPACE_CHECK_RESERVED, + .blocks_modified = 1, + .pargs = { + {.za_name = "filesystem", .za_lua_type = LUA_TSTRING}, + {0, 0} + }, + .kwargs = { + {0, 0} + } +}; + +static int +zcp_synctask_rollback(lua_State *state, boolean_t sync, nvlist_t *err_details) +{ + int err; + const char *dsname = lua_tostring(state, 1); + dsl_dataset_rollback_arg_t ddra = { 0 }; + + ddra.ddra_fsname = dsname; + ddra.ddra_result = err_details; + + err = zcp_sync_task(state, dsl_dataset_rollback_check, + dsl_dataset_rollback_sync, &ddra, sync, dsname); + + return (err); +} + void zcp_synctask_wrapper_cleanup(void *arg) { @@ -247,6 +278,7 @@ zcp_load_synctask_lib(lua_State *state, boolean_t sync) zcp_synctask_info_t *zcp_synctask_funcs[] = { &zcp_synctask_destroy_info, &zcp_synctask_promote_info, + &zcp_synctask_rollback_info, NULL }; diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run index 04f0163f3f..0320301d24 100644 --- a/tests/runfiles/linux.run +++ b/tests/runfiles/linux.run @@ -77,8 +77,8 @@ tests = ['tst.destroy_fs', 'tst.destroy_snap', 'tst.get_count_and_limit', 'tst.get_number_props', 'tst.get_string_props', 'tst.get_type', 'tst.get_userquota', 'tst.get_written', 'tst.list_children', 'tst.list_clones', 'tst.list_snapshots', 'tst.list_system_props', - 'tst.parse_args_neg','tst.promote_conflict', 'tst.promote_multiple', - 'tst.promote_simple'] + 'tst.parse_args_neg', 'tst.promote_conflict', 'tst.promote_multiple', + 'tst.promote_simple', 'tst.rollback_mult', 'tst.rollback_one'] tags = ['functional', 'channel_program', 'synctask_core'] [tests/functional/chattr] diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/Makefile.am b/tests/zfs-tests/tests/functional/channel_program/synctask_core/Makefile.am index cd347472c5..29bd68eeea 100644 --- a/tests/zfs-tests/tests/functional/channel_program/synctask_core/Makefile.am +++ b/tests/zfs-tests/tests/functional/channel_program/synctask_core/Makefile.am @@ -27,4 +27,6 @@ dist_pkgdata_SCRIPTS = \ tst.promote_conflict.ksh \ tst.promote_conflict.zcp \ tst.promote_multiple.ksh \ - tst.promote_simple.ksh + tst.promote_simple.ksh \ + tst.rollback_mult.ksh \ + tst.rollback_one.ksh diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.rollback_mult.ksh b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.rollback_mult.ksh new file mode 100755 index 0000000000..778abc09dd --- /dev/null +++ b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.rollback_mult.ksh @@ -0,0 +1,61 @@ +#!/bin/ksh -p +# +# 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. +# + +# +# Copyright (c) 2016, 2017 by Delphix. All rights reserved. +# + +. $STF_SUITE/tests/functional/channel_program/channel_common.kshlib + +verify_runnable "global" +snap1=$TESTPOOL/$TESTFS@$TESTSNAP1 +snap2=$TESTPOOL/$TESTFS@$TESTSNAP2 +fs=$TESTPOOL/$TESTFS +file=$TESTDIR/$TESTFILE0 + +function cleanup +{ + datasetexists $snap1 && log_must zfs destroy $snap1 && \ + log_must rm $file +} + +log_onexit cleanup + +log_must mkfile 128b $file +create_snapshot $TESTPOOL/$TESTFS $TESTSNAP1 +log_must rm $file +create_snapshot $TESTPOOL/$TESTFS $TESTSNAP2 + +log_must snapexists $snap1 +log_must snapexists $snap2 +log_must zfs unmount $fs + +log_must_program $TESTPOOL - $fs $snap2 <<-EOF + arg = ... + fs = arg["argv"][1] + snap = arg["argv"][2] + err = zfs.sync.rollback(fs) + if err == 0 then + err = zfs.sync.destroy(snap) + end + if err == 0 then + err = zfs.sync.rollback(fs) + end + msg = "rolling back " .. fs .. " err=" .. err + return msg +EOF + +log_must zfs mount $fs +log_must [ -f $file ] +log_mustnot snapexists $snap2 + +log_pass "Rolling back snapshot with channel program works." diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.rollback_one.ksh b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.rollback_one.ksh new file mode 100755 index 0000000000..2a8e83913b --- /dev/null +++ b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.rollback_one.ksh @@ -0,0 +1,51 @@ +#!/bin/ksh -p +# +# 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. +# + +# +# Copyright (c) 2016, 2017 by Delphix. All rights reserved. +# + +. $STF_SUITE/tests/functional/channel_program/channel_common.kshlib + +verify_runnable "global" +snap=$TESTPOOL/$TESTFS@$TESTSNAP +fs=$TESTPOOL/$TESTFS +file=$TESTDIR/$TESTFILE0 + +function cleanup +{ + datasetexists $snap && log_must zfs destroy $snap && \ + log_must rm $file + +} + +log_onexit cleanup + +log_must mkfile 128b $file +create_snapshot $TESTPOOL/$TESTFS $TESTSNAP +log_must rm $file + +log_must snapexists $snap +log_must zfs unmount $fs + +log_must_program $TESTPOOL - $fs <<-EOF + arg = ... + fs = arg["argv"][1] + err = zfs.sync.rollback(fs) + msg = "rolling back " .. fs .. " err=" .. err + return msg +EOF + +log_must zfs mount $fs +log_must [ -f $file ] + +log_pass "Rolling back snapshot with channel program works."