From ee9f3bca5574192589d7c7734fdc81b361aa77db Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Fri, 2 Sep 2022 23:31:19 +0300 Subject: [PATCH] Add zfs.sync.snapshot_rename Only the single snapshot rename is provided. The recursive or more complex rename can be scripted. Reviewed-by: Brian Behlendorf Reviewed-by: George Melikov Signed-off-by: Andriy Gapon Closes #13802 --- include/sys/dsl_dataset.h | 11 +++++ man/man8/zfs-program.8 | 13 ++++++ module/zfs/dsl_dataset.c | 12 +----- module/zfs/zcp_synctask.c | 37 +++++++++++++++++ tests/zfs-tests/tests/Makefile.am | 2 + .../synctask_core/tst.snapshot_rename.ksh | 41 +++++++++++++++++++ .../synctask_core/tst.snapshot_rename.zcp | 27 ++++++++++++ 7 files changed, 133 insertions(+), 10 deletions(-) create mode 100755 tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_rename.ksh create mode 100644 tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_rename.zcp diff --git a/include/sys/dsl_dataset.h b/include/sys/dsl_dataset.h index 81d25da831..3450527af7 100644 --- a/include/sys/dsl_dataset.h +++ b/include/sys/dsl_dataset.h @@ -301,6 +301,14 @@ typedef struct dsl_dataset_snapshot_arg { proc_t *ddsa_proc; } dsl_dataset_snapshot_arg_t; +typedef struct dsl_dataset_rename_snapshot_arg { + const char *ddrsa_fsname; + const char *ddrsa_oldsnapname; + const char *ddrsa_newsnapname; + boolean_t ddrsa_recursive; + dmu_tx_t *ddrsa_tx; +} dsl_dataset_rename_snapshot_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. @@ -473,6 +481,9 @@ 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); +int dsl_dataset_rename_snapshot_check(void *arg, dmu_tx_t *tx); +void dsl_dataset_rename_snapshot_sync(void *arg, dmu_tx_t *tx); + uint64_t dsl_dataset_get_remap_deadlist_object(dsl_dataset_t *ds); void dsl_dataset_create_remap_deadlist(dsl_dataset_t *ds, dmu_tx_t *tx); boolean_t dsl_dataset_remap_deadlist_exists(dsl_dataset_t *ds); diff --git a/man/man8/zfs-program.8 b/man/man8/zfs-program.8 index 06415b2190..928620362b 100644 --- a/man/man8/zfs-program.8 +++ b/man/man8/zfs-program.8 @@ -424,6 +424,19 @@ To enable taking snapshots from ZCP scripts, the pool must be upgraded. .It Ar dataset Pq string Name of snapshot to create. .El +.It Fn zfs.sync.rename_snapshot dataset oldsnapname newsnapname +Rename a snapshot of a filesystem or a volume. +Returns 0 if the snapshot was successfully renamed, +and a nonzero error code otherwise. +.Pp +.Bl -tag -compact -width "newbookmark (string)" +.It Ar dataset Pq string +Name of the snapshot's parent dataset. +.It Ar oldsnapname Pq string +Original name of the snapshot. +.It Ar newsnapname Pq string +New name of the snapshot. +.El .It Fn zfs.sync.bookmark source newbookmark Create a bookmark of an existing source snapshot or bookmark. Returns 0 if the new bookmark was successfully created, diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 8f3240a5de..44da6a3f0d 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -2915,14 +2915,6 @@ dsl_dataset_modified_since_snap(dsl_dataset_t *ds, dsl_dataset_t *snap) return (B_FALSE); } -typedef struct dsl_dataset_rename_snapshot_arg { - const char *ddrsa_fsname; - const char *ddrsa_oldsnapname; - const char *ddrsa_newsnapname; - boolean_t ddrsa_recursive; - dmu_tx_t *ddrsa_tx; -} dsl_dataset_rename_snapshot_arg_t; - static int dsl_dataset_rename_snapshot_check_impl(dsl_pool_t *dp, dsl_dataset_t *hds, void *arg) @@ -2953,7 +2945,7 @@ dsl_dataset_rename_snapshot_check_impl(dsl_pool_t *dp, return (error); } -static int +int dsl_dataset_rename_snapshot_check(void *arg, dmu_tx_t *tx) { dsl_dataset_rename_snapshot_arg_t *ddrsa = arg; @@ -3015,7 +3007,7 @@ dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp, return (0); } -static void +void dsl_dataset_rename_snapshot_sync(void *arg, dmu_tx_t *tx) { dsl_dataset_rename_snapshot_arg_t *ddrsa = arg; diff --git a/module/zfs/zcp_synctask.c b/module/zfs/zcp_synctask.c index 24210117ec..058910054d 100644 --- a/module/zfs/zcp_synctask.c +++ b/module/zfs/zcp_synctask.c @@ -302,6 +302,42 @@ zcp_synctask_snapshot(lua_State *state, boolean_t sync, nvlist_t *err_details) return (err); } +static int zcp_synctask_rename_snapshot(lua_State *, boolean_t, nvlist_t *); +static const zcp_synctask_info_t zcp_synctask_rename_snapshot_info = { + .name = "rename_snapshot", + .func = zcp_synctask_rename_snapshot, + .pargs = { + {.za_name = "filesystem | volume", .za_lua_type = LUA_TSTRING }, + {.za_name = "oldsnapname", .za_lua_type = LUA_TSTRING }, + {.za_name = "newsnapname", .za_lua_type = LUA_TSTRING }, + {NULL, 0} + }, + .space_check = ZFS_SPACE_CHECK_RESERVED, + .blocks_modified = 1 +}; + +static int +zcp_synctask_rename_snapshot(lua_State *state, boolean_t sync, + nvlist_t *err_details) +{ + (void) err_details; + int err; + const char *fsname = lua_tostring(state, 1); + const char *oldsnapname = lua_tostring(state, 2); + const char *newsnapname = lua_tostring(state, 3); + + struct dsl_dataset_rename_snapshot_arg ddrsa = { 0 }; + ddrsa.ddrsa_fsname = fsname; + ddrsa.ddrsa_oldsnapname = oldsnapname; + ddrsa.ddrsa_newsnapname = newsnapname; + ddrsa.ddrsa_recursive = B_FALSE; + + err = zcp_sync_task(state, dsl_dataset_rename_snapshot_check, + dsl_dataset_rename_snapshot_sync, &ddrsa, sync, NULL); + + return (err); +} + static int zcp_synctask_inherit_prop(lua_State *, boolean_t, nvlist_t *err_details); static const zcp_synctask_info_t zcp_synctask_inherit_prop_info = { @@ -529,6 +565,7 @@ zcp_load_synctask_lib(lua_State *state, boolean_t sync) &zcp_synctask_promote_info, &zcp_synctask_rollback_info, &zcp_synctask_snapshot_info, + &zcp_synctask_rename_snapshot_info, &zcp_synctask_inherit_prop_info, &zcp_synctask_bookmark_info, &zcp_synctask_set_prop_info, diff --git a/tests/zfs-tests/tests/Makefile.am b/tests/zfs-tests/tests/Makefile.am index b80489af25..89b2ca866c 100644 --- a/tests/zfs-tests/tests/Makefile.am +++ b/tests/zfs-tests/tests/Makefile.am @@ -129,6 +129,7 @@ nobase_dist_datadir_zfs_tests_tests_DATA += \ functional/channel_program/synctask_core/tst.snapshot_destroy.zcp \ functional/channel_program/synctask_core/tst.snapshot_neg.zcp \ functional/channel_program/synctask_core/tst.snapshot_recursive.zcp \ + functional/channel_program/synctask_core/tst.snapshot_rename.zcp \ functional/channel_program/synctask_core/tst.snapshot_simple.zcp \ functional/checksum/default.cfg \ functional/clean_mirror/clean_mirror_common.kshlib \ @@ -536,6 +537,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/channel_program/synctask_core/tst.snapshot_destroy.ksh \ functional/channel_program/synctask_core/tst.snapshot_neg.ksh \ functional/channel_program/synctask_core/tst.snapshot_recursive.ksh \ + functional/channel_program/synctask_core/tst.snapshot_rename.ksh \ functional/channel_program/synctask_core/tst.snapshot_simple.ksh \ functional/channel_program/synctask_core/tst.terminate_by_signal.ksh \ functional/chattr/chattr_001_pos.ksh \ diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_rename.ksh b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_rename.ksh new file mode 100755 index 0000000000..0561e4b7c6 --- /dev/null +++ b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_rename.ksh @@ -0,0 +1,41 @@ +#!/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) 2022 by Andriy Gapon. All rights reserved. +# + +. $STF_SUITE/tests/functional/channel_program/channel_common.kshlib + +# +# DESCRIPTION: Make sure basic snapshot functionality works in channel programs +# + +verify_runnable "global" + +fs=$TESTPOOL/$TESTFS/testchild +snapname1=testsnap1 +snapname2=testsnap2 + +function cleanup +{ + destroy_dataset $fs "-R" +} + +log_onexit cleanup + +log_must zfs create $fs + +log_must_program_sync $TESTPOOL \ + $ZCP_ROOT/synctask_core/tst.snapshot_rename.zcp $fs $snapname1 $snapname2 + +log_pass "Snapshot renaming works" diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_rename.zcp b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_rename.zcp new file mode 100644 index 0000000000..ef893d1551 --- /dev/null +++ b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.snapshot_rename.zcp @@ -0,0 +1,27 @@ +-- +-- 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) 2022 by Andriy Gapon. All rights reserved. +-- + +-- This program should be invoked as "zfs program " + +args = ... +argv = args["argv"] +assert(zfs.sync.snapshot(argv[1] .. "@" .. argv[2]) == 0) +assert(zfs.sync.rename_snapshot(argv[1], argv[2], argv[3]) == 0) +snaps = {} +for s in zfs.list.snapshots(argv[1]) do + table.insert(snaps, s) +end +assert(#snaps == 1) +assert(snaps[1] == (argv[1] .. "@" .. argv[3]))