diff options
author | Christian Schwarz <[email protected]> | 2020-01-16 02:15:05 +0100 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2020-02-11 13:19:17 -0800 |
commit | 948f0c44196d2fa254399ec0d716c2ba0bb9ffad (patch) | |
tree | 87307e1d30a2f0601f64bb75603aedeb70f73b54 | |
parent | a73f361fdb2c0a7778e70b482e316054fc2d8630 (diff) |
zcp: add zfs.sync.bookmark
Add support for bookmark creation and cloning.
Reviewed-by: Matt Ahrens <[email protected]>
Reviewed-by: Paul Dagnelie <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Christian Schwarz <[email protected]>
Closes #9571
10 files changed, 231 insertions, 17 deletions
diff --git a/include/sys/dsl_bookmark.h b/include/sys/dsl_bookmark.h index ec3895d40..73424e5a8 100644 --- a/include/sys/dsl_bookmark.h +++ b/include/sys/dsl_bookmark.h @@ -102,8 +102,25 @@ typedef struct redact_block_phys { typedef int (*rl_traverse_callback_t)(redact_block_phys_t *, void *); + +typedef struct dsl_bookmark_create_arg { + nvlist_t *dbca_bmarks; + nvlist_t *dbca_errors; +} dsl_bookmark_create_arg_t; + +typedef struct dsl_bookmark_create_redacted_arg { + const char *dbcra_bmark; + const char *dbcra_snap; + redaction_list_t **dbcra_rl; + uint64_t dbcra_numsnaps; + uint64_t *dbcra_snaps; + void *dbcra_tag; +} dsl_bookmark_create_redacted_arg_t; + int dsl_bookmark_create(nvlist_t *, nvlist_t *); int dsl_bookmark_create_nvl_validate(nvlist_t *); +int dsl_bookmark_create_check(void *arg, dmu_tx_t *tx); +void dsl_bookmark_create_sync(void *arg, dmu_tx_t *tx); int dsl_bookmark_create_redacted(const char *, const char *, uint64_t, uint64_t *, void *, redaction_list_t **); int dsl_get_bookmarks(const char *, nvlist_t *, nvlist_t *); diff --git a/man/man8/zfs-program.8 b/man/man8/zfs-program.8 index f953cf18f..c754fcf99 100644 --- a/man/man8/zfs-program.8 +++ b/man/man8/zfs-program.8 @@ -9,6 +9,7 @@ .\" .\" .\" Copyright (c) 2016, 2019 by Delphix. All Rights Reserved. +.\" Copyright (c) 2019, 2020 by Christian Schwarz. All Rights Reserved. .\" Copyright 2020 Joyent, Inc. .\" .Dd January 15, 2020 @@ -419,6 +420,21 @@ dataset (string) .Bd -ragged -compact -offset "xxxx" Name of snapshot to create. .Ed +.It Em zfs.sync.bookmark(source, newbookmark) +Create a bookmark of an existing source snapshot or bookmark. +Returns 0 if the new bookmark was successfully created, +and a nonzero error code otherwise. +.Pp +Note: Bookmarking requires the corresponding pool feature to be enabled. +.Pp +source (string) +.Bd -ragged -compact -offset "xxxx" +Full name of the existing snapshot or bookmark. +.Ed +.Pp +newbookmark (string) +.Bd -ragged -compact -offset "xxxx" +Full name of the new bookmark. .El .It Sy zfs.check submodule For each function in the zfs.sync submodule, there is a corresponding zfs.check diff --git a/module/zfs/dsl_bookmark.c b/module/zfs/dsl_bookmark.c index 5a73c5300..45ba4b557 100644 --- a/module/zfs/dsl_bookmark.c +++ b/module/zfs/dsl_bookmark.c @@ -205,20 +205,6 @@ dsl_bookmark_create_nvl_validate(nvlist_t *bmarks) return (0); } -typedef struct dsl_bookmark_create_redacted_arg { - const char *dbcra_bmark; - const char *dbcra_snap; - redaction_list_t **dbcra_rl; - uint64_t dbcra_numsnaps; - uint64_t *dbcra_snaps; - void *dbcra_tag; -} dsl_bookmark_create_redacted_arg_t; - -typedef struct dsl_bookmark_create_arg { - nvlist_t *dbca_bmarks; - nvlist_t *dbca_errors; -} dsl_bookmark_create_arg_t; - /* * expects that newbm and source have been validated using * dsl_bookmark_create_nvl_validate_pair @@ -301,7 +287,7 @@ eholdnewbmds: return (error); } -static int +int dsl_bookmark_create_check(void *arg, dmu_tx_t *tx) { dsl_bookmark_create_arg_t *dbca = arg; diff --git a/module/zfs/zcp_synctask.c b/module/zfs/zcp_synctask.c index 22fec6f3f..a6f7a04c7 100644 --- a/module/zfs/zcp_synctask.c +++ b/module/zfs/zcp_synctask.c @@ -15,6 +15,7 @@ /* * Copyright (c) 2016, 2017 by Delphix. All rights reserved. + * Copyright (c) 2019, 2020 by Christian Schwarz. All rights reserved. * Copyright 2020 Joyent, Inc. */ @@ -370,6 +371,49 @@ zcp_synctask_inherit_prop(lua_State *state, boolean_t sync, return (err); } +static int zcp_synctask_bookmark(lua_State *, boolean_t, nvlist_t *); +static zcp_synctask_info_t zcp_synctask_bookmark_info = { + .name = "bookmark", + .func = zcp_synctask_bookmark, + .pargs = { + {.za_name = "snapshot | bookmark", .za_lua_type = LUA_TSTRING}, + {.za_name = "bookmark", .za_lua_type = LUA_TSTRING}, + {NULL, 0} + }, + .kwargs = { + {NULL, 0} + }, + .space_check = ZFS_SPACE_CHECK_NORMAL, + .blocks_modified = 1, +}; + +/* ARGSUSED */ +static int +zcp_synctask_bookmark(lua_State *state, boolean_t sync, nvlist_t *err_details) +{ + int err; + const char *source = lua_tostring(state, 1); + const char *new = lua_tostring(state, 2); + + nvlist_t *bmarks = fnvlist_alloc(); + fnvlist_add_string(bmarks, new, source); + + zcp_cleanup_handler_t *zch = zcp_register_cleanup(state, + (zcp_cleanup_t *)&fnvlist_free, bmarks); + + dsl_bookmark_create_arg_t dbca = { + .dbca_bmarks = bmarks, + .dbca_errors = NULL, + }; + err = zcp_sync_task(state, dsl_bookmark_create_check, + dsl_bookmark_create_sync, &dbca, sync, source); + + zcp_deregister_cleanup(state, zch); + fnvlist_free(bmarks); + + return (err); +} + static int zcp_synctask_wrapper(lua_State *state) { @@ -439,6 +483,7 @@ zcp_load_synctask_lib(lua_State *state, boolean_t sync) &zcp_synctask_rollback_info, &zcp_synctask_snapshot_info, &zcp_synctask_inherit_prop_info, + &zcp_synctask_bookmark_info, NULL }; diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index 691cae9cb..e4593a53e 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -87,7 +87,7 @@ tests = ['tst.destroy_fs', 'tst.destroy_snap', 'tst.get_count_and_limit', 'tst.promote_multiple', 'tst.promote_simple', 'tst.rollback_mult', 'tst.rollback_one', 'tst.snapshot_destroy', 'tst.snapshot_neg', 'tst.snapshot_recursive', 'tst.snapshot_simple', - 'tst.bookmark.create', 'tst.bookmark.clone', + 'tst.bookmark.create', 'tst.bookmark.copy', 'tst.terminate_by_signal' ] tags = ['functional', 'channel_program', 'synctask_core'] 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 5330edaf2..e74c5223b 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 @@ -30,6 +30,8 @@ dist_pkgdata_SCRIPTS = \ tst.snapshot_destroy.ksh \ tst.snapshot_neg.ksh \ tst.snapshot_recursive.ksh \ + tst.bookmark.create.ksh \ + tst.bookmark.copy.ksh \ tst.snapshot_simple.ksh \ tst.terminate_by_signal.ksh @@ -44,4 +46,6 @@ dist_pkgdata_DATA = \ tst.snapshot_destroy.zcp \ tst.snapshot_neg.zcp \ tst.snapshot_recursive.zcp \ - tst.snapshot_simple.zcp + tst.snapshot_simple.zcp \ + tst.bookmark.create.zcp \ + tst.bookmark.copy.zcp diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.bookmark.copy.ksh b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.bookmark.copy.ksh new file mode 100755 index 000000000..81f570d9e --- /dev/null +++ b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.bookmark.copy.ksh @@ -0,0 +1,45 @@ +#!/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) 2019, 2020 by Christian Schwarz. All rights reserved. +# + +. $STF_SUITE/tests/functional/channel_program/channel_common.kshlib + +# +# DESCRIPTION: Make sure bookmark copying works in channel programs +# + +verify_runnable "global" + +fs=$TESTPOOL/$TESTFS/testchild +snapname=testsnap +bookname=testbookmark +bookcopyname=testbookmark_copy + +function cleanup +{ + destroy_dataset $fs "-R" +} + +log_onexit cleanup + +log_must zfs create $fs + +log_must zfs snapshot $fs@$snapname +log_must zfs bookmark $fs@$snapname "$fs#$bookname" + +log_must_program_sync $TESTPOOL \ + $ZCP_ROOT/synctask_core/tst.bookmark.copy.zcp $fs $bookname $bookcopyname + +log_pass "Simple bookmark copying works" diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.bookmark.copy.zcp b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.bookmark.copy.zcp new file mode 100644 index 000000000..9473035f0 --- /dev/null +++ b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.bookmark.copy.zcp @@ -0,0 +1,32 @@ +-- +-- 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) 2019, 2020 by Christian Schwarz. All rights reserved. +-- + +-- This program should be invoked as "zfs program <pool> <prog> <fs> <source_book> <new_book>" + +args = ... +argv = args["argv"] +fs = argv[1] +source = fs .. "#" .. argv[2] +new = fs .. "#" .. argv[3] +assert(zfs.sync.bookmark(source, new) == 0) +books = {} +count = 0 +for s in zfs.list.bookmarks(fs) do + count = count + 1 + books[s] = 1 +end +assert(count == 2) +assert(books[source] == 1) +assert(books[new] == 1) diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.bookmark.create.ksh b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.bookmark.create.ksh new file mode 100755 index 000000000..05ec9cc67 --- /dev/null +++ b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.bookmark.create.ksh @@ -0,0 +1,43 @@ +#!/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) 2019, 2020 by Christian Schwarz. All rights reserved. +# + +. $STF_SUITE/tests/functional/channel_program/channel_common.kshlib + +# +# DESCRIPTION: Make sure basic bookmark functionality works in channel programs +# + +verify_runnable "global" + +fs=$TESTPOOL/$TESTFS/testchild +snapname=testsnap +bookname=testbookmark + +function cleanup +{ + destroy_dataset $fs "-R" +} + +log_onexit cleanup + +log_must zfs create $fs + +log_must zfs snapshot $fs@$snapname + +log_must_program_sync $TESTPOOL \ + $ZCP_ROOT/synctask_core/tst.bookmark.create.zcp $fs $snapname $bookname + +log_pass "Simple bookmark creation works" diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.bookmark.create.zcp b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.bookmark.create.zcp new file mode 100644 index 000000000..eb53fd16c --- /dev/null +++ b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.bookmark.create.zcp @@ -0,0 +1,26 @@ +-- +-- 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) 2019, 2020 by Christian Schwarz. All rights reserved. +-- + +-- This program should be invoked as "zfs program <pool> <prog> <fs> <snap> <book>" + +args = ... +argv = args["argv"] +assert(zfs.sync.bookmark(argv[1] .. "@" .. argv[2], argv[1] .. "#" .. argv[3]) == 0) +books = {} +for s in zfs.list.bookmarks(argv[1]) do + table.insert(books, s) +end +assert(#books == 1) +assert(books[1] == (argv[1] .. "#" .. argv[3])) |