From e2ef1cbf04c713fcdba33f8183e6a61a18f61119 Mon Sep 17 00:00:00 2001 From: Jason King Date: Wed, 22 Jan 2020 19:03:17 -0600 Subject: [PATCH] Support inheriting properties in channel programs This adds support in channel programs to inherit properties analogous to `zfs inherit` by adding `zfs.sync.inherit` and `zfs.check.inherit` functions to the ZFS LUA API. Reviewed-by: Brian Behlendorf Signed-off-by: Jason King Closes #9738 --- include/sys/dsl_prop.h | 9 ++ man/man8/zfs-program.8 | 24 +++++- module/zfs/dsl_prop.c | 12 +-- module/zfs/zcp_synctask.c | 86 +++++++++++++++++++ tests/runfiles/common.run | 2 +- .../channel_program/synctask_core/Makefile.am | 1 + .../synctask_core/tst.inherit.ksh | 39 +++++++++ 7 files changed, 162 insertions(+), 11 deletions(-) create mode 100755 tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.inherit.ksh diff --git a/include/sys/dsl_prop.h b/include/sys/dsl_prop.h index 62ef0ba67..fba8f908d 100644 --- a/include/sys/dsl_prop.h +++ b/include/sys/dsl_prop.h @@ -21,6 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. + * Copyright 2019 Joyent, Inc. */ #ifndef _SYS_DSL_PROP_H @@ -61,6 +62,12 @@ typedef struct dsl_props_arg { zprop_source_t pa_source; } dsl_props_arg_t; +typedef struct dsl_props_set_arg { + const char *dpsa_dsname; + zprop_source_t dpsa_source; + nvlist_t *dpsa_props; +} dsl_props_set_arg_t; + void dsl_prop_init(dsl_dir_t *dd); void dsl_prop_fini(dsl_dir_t *dd); int dsl_prop_register(struct dsl_dataset *ds, const char *propname, @@ -85,6 +92,8 @@ int dsl_prop_get_dd(struct dsl_dir *dd, const char *propname, int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot); +int dsl_props_set_check(void *arg, dmu_tx_t *tx); +void dsl_props_set_sync(void *arg, dmu_tx_t *tx); void dsl_props_set_sync_impl(struct dsl_dataset *ds, zprop_source_t source, nvlist_t *props, dmu_tx_t *tx); void dsl_prop_set_sync_impl(struct dsl_dataset *ds, const char *propname, diff --git a/man/man8/zfs-program.8 b/man/man8/zfs-program.8 index 7c58af0d2..f953cf18f 100644 --- a/man/man8/zfs-program.8 +++ b/man/man8/zfs-program.8 @@ -9,8 +9,9 @@ .\" .\" .\" Copyright (c) 2016, 2019 by Delphix. All Rights Reserved. +.\" Copyright 2020 Joyent, Inc. .\" -.Dd February 26, 2019 +.Dd January 15, 2020 .Dt ZFS-PROGRAM 8 .Os .Sh NAME @@ -364,6 +365,27 @@ Valid only for destroying snapshots. If set to true, and the snapshot has holds or clones, allows the snapshot to be marked for deferred deletion rather than failing. .Ed +.It Em zfs.sync.inherit(dataset, property) +Clears the specified property in the given dataset, causing it to be inherited +from an ancestor, or restored to the default if no ancestor property is set. +The +.Ql zfs inherit -S +option has not been implemented. +Returns 0 on success, or a nonzero error code if the property could not be +cleared. +.Pp +dataset (string) +.Bd -ragged -compact -offset "xxxx" +Filesystem or snapshot containing the property to clear. +.Ed +.Pp +property (string) +.Bd -ragged -compact -offset "xxxx" +The property to clear. +Allowed properties are the same as those for the +.Nm zfs Cm inherit +command. +.Ed .It Em zfs.sync.promote(dataset) Promote the given clone to a filesystem. Returns 0 on successful promotion, or a nonzero error code otherwise. diff --git a/module/zfs/dsl_prop.c b/module/zfs/dsl_prop.c index 4c468de5f..1c99f3b75 100644 --- a/module/zfs/dsl_prop.c +++ b/module/zfs/dsl_prop.c @@ -22,7 +22,7 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2015 by Delphix. All rights reserved. * Copyright (c) 2013 Martin Matuska. All rights reserved. - * Copyright 2015, Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #include @@ -856,13 +856,7 @@ dsl_prop_inherit(const char *dsname, const char *propname, return (error); } -typedef struct dsl_props_set_arg { - const char *dpsa_dsname; - zprop_source_t dpsa_source; - nvlist_t *dpsa_props; -} dsl_props_set_arg_t; - -static int +int dsl_props_set_check(void *arg, dmu_tx_t *tx) { dsl_props_set_arg_t *dpsa = arg; @@ -940,7 +934,7 @@ dsl_props_set_sync_impl(dsl_dataset_t *ds, zprop_source_t source, } } -static void +void dsl_props_set_sync(void *arg, dmu_tx_t *tx) { dsl_props_set_arg_t *dpsa = arg; diff --git a/module/zfs/zcp_synctask.c b/module/zfs/zcp_synctask.c index e089666f2..3b6015f24 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 2020 Joyent, Inc. */ #include @@ -35,6 +36,12 @@ #define DST_AVG_BLKSHIFT 14 +typedef struct zcp_inherit_prop_arg { + lua_State *zipa_state; + const char *zipa_prop; + dsl_props_set_arg_t zipa_dpsa; +} zcp_inherit_prop_arg_t; + typedef int (zcp_synctask_func_t)(lua_State *, boolean_t, nvlist_t *); typedef struct zcp_synctask_info { const char *name; @@ -275,6 +282,84 @@ zcp_synctask_snapshot(lua_State *state, boolean_t sync, nvlist_t *err_details) return (err); } +static int zcp_synctask_inherit_prop(lua_State *, boolean_t, + nvlist_t *err_details); +static zcp_synctask_info_t zcp_synctask_inherit_prop_info = { + .name = "inherit", + .func = zcp_synctask_inherit_prop, + .space_check = ZFS_SPACE_CHECK_RESERVED, + .blocks_modified = 2, /* 2 * numprops */ + .pargs = { + { .za_name = "dataset", .za_lua_type = LUA_TSTRING }, + { .za_name = "property", .za_lua_type = LUA_TSTRING }, + { NULL, 0 } + }, + .kwargs = { + { NULL, 0 } + }, +}; + +static int +zcp_synctask_inherit_prop_check(void *arg, dmu_tx_t *tx) +{ + zcp_inherit_prop_arg_t *args = arg; + zfs_prop_t prop = zfs_name_to_prop(args->zipa_prop); + + if (prop == ZPROP_INVAL) { + if (zfs_prop_user(args->zipa_prop)) + return (0); + + return (EINVAL); + } + + if (zfs_prop_readonly(prop)) + return (EINVAL); + + if (!zfs_prop_inheritable(prop)) + return (EINVAL); + + return (dsl_props_set_check(&args->zipa_dpsa, tx)); +} + +static void +zcp_synctask_inherit_prop_sync(void *arg, dmu_tx_t *tx) +{ + zcp_inherit_prop_arg_t *args = arg; + dsl_props_set_arg_t *dpsa = &args->zipa_dpsa; + + dsl_props_set_sync(dpsa, tx); +} + +static int +zcp_synctask_inherit_prop(lua_State *state, boolean_t sync, + nvlist_t *err_details) +{ + int err; + zcp_inherit_prop_arg_t zipa = { 0 }; + dsl_props_set_arg_t *dpsa = &zipa.zipa_dpsa; + + const char *dsname = lua_tostring(state, 1); + const char *prop = lua_tostring(state, 2); + + zipa.zipa_state = state; + zipa.zipa_prop = prop; + dpsa->dpsa_dsname = dsname; + dpsa->dpsa_source = ZPROP_SRC_INHERITED; + dpsa->dpsa_props = fnvlist_alloc(); + fnvlist_add_boolean(dpsa->dpsa_props, prop); + + zcp_cleanup_handler_t *zch = zcp_register_cleanup(state, + (zcp_cleanup_t *)&fnvlist_free, dpsa->dpsa_props); + + err = zcp_sync_task(state, zcp_synctask_inherit_prop_check, + zcp_synctask_inherit_prop_sync, &zipa, sync, dsname); + + zcp_deregister_cleanup(state, zch); + fnvlist_free(dpsa->dpsa_props); + + return (err); +} + static int zcp_synctask_wrapper(lua_State *state) { @@ -343,6 +428,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_inherit_prop_info, NULL }; diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index 4342662e7..f93f6479a 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -80,7 +80,7 @@ tags = ['functional', 'channel_program', 'lua_core'] tests = ['tst.destroy_fs', 'tst.destroy_snap', 'tst.get_count_and_limit', 'tst.get_index_props', 'tst.get_mountpoint', 'tst.get_neg', 'tst.get_number_props', 'tst.get_string_props', 'tst.get_type', - 'tst.get_userquota', 'tst.get_written', 'tst.list_bookmarks', + 'tst.get_userquota', 'tst.get_written', 'tst.inherit', 'tst.list_bookmarks', 'tst.list_children', 'tst.list_clones', 'tst.list_holds', 'tst.list_snapshots', 'tst.list_system_props', 'tst.list_user_props', 'tst.parse_args_neg','tst.promote_conflict', 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 d9894f682..5330edaf2 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 @@ -13,6 +13,7 @@ dist_pkgdata_SCRIPTS = \ tst.get_type.ksh \ tst.get_userquota.ksh \ tst.get_written.ksh \ + tst.inherit.ksh \ tst.list_bookmarks.ksh \ tst.list_children.ksh \ tst.list_clones.ksh \ diff --git a/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.inherit.ksh b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.inherit.ksh new file mode 100755 index 000000000..e199b4c8b --- /dev/null +++ b/tests/zfs-tests/tests/functional/channel_program/synctask_core/tst.inherit.ksh @@ -0,0 +1,39 @@ +#!/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 2020 Joyent, Inc. +# + +. $STF_SUITE/tests/functional/channel_program/channel_common.kshlib + +verify_runnable "global" + +fs=$TESTPOOL/$TESTFS +testprop="com.joyent:testprop" +testval="testval" + +log_must dataset_setprop $fs $testprop $testval +log_must_program_sync $TESTPOOL - $fs $testprop <<-EOF + arg = ... + fs = arg["argv"][1] + prop = arg["argv"][2] + err = zfs.sync.inherit(fs, prop) + msg = "resetting " .. prop .. " on " .. fs .. " err=" .. err + return msg +EOF + + +prop=$(get_prop $testprop $fs) +[[ "$prop" == "-" ]] || log_fail "Property still set after inheriting" + +log_pass "Inherit/clear property with channel program works."